@@ -1493,44 +1493,65 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_locale_compare(duk_hthread *thr)
14931493#if defined(DUK_USE_ES6 )
14941494DUK_INTERNAL duk_ret_t duk_bi_string_prototype_startswith_endswith (duk_hthread * thr ) {
14951495 duk_int_t magic ;
1496- duk_hstring * h ;
1496+ duk_hstring * h_target ;
1497+ duk_size_t blen_target ;
14971498 duk_hstring * h_search ;
14981499 duk_size_t blen_search ;
1499- const duk_uint8_t * p_cmp_start ;
1500- duk_bool_t result ;
1500+ duk_int_t off ;
1501+ duk_bool_t result = 0 ;
1502+ duk_size_t blen_left ;
15011503
1502- h = duk_push_this_coercible_to_string (thr );
1503- DUK_ASSERT (h != NULL );
1504+ /* Because string byte lengths are in [0,DUK_INT_MAX] it's safe to
1505+ * subtract two string lengths without overflow.
1506+ */
1507+ DUK_ASSERT (DUK_HSTRING_MAX_BYTELEN <= DUK_INT_MAX );
1508+
1509+ h_target = duk_push_this_coercible_to_string (thr );
1510+ DUK_ASSERT (h_target != NULL );
15041511
15051512 h_search = duk__str_tostring_notregexp (thr , 0 );
15061513 DUK_ASSERT (h_search != NULL );
15071514
15081515 magic = duk_get_current_magic (thr );
15091516
1510- p_cmp_start = (const duk_uint8_t * ) DUK_HSTRING_GET_DATA (h );
1517+ /* Careful to avoid pointer overflows in the matching logic. */
1518+
1519+ blen_target = DUK_HSTRING_GET_BYTELEN (h_target );
15111520 blen_search = DUK_HSTRING_GET_BYTELEN (h_search );
15121521
1522+ #if 0
1523+ /* If search string is longer than the target string, we can
1524+ * never match. Could check explicitly, but should be handled
1525+ * correctly below.
1526+ */
1527+ if (blen_search > blen_target ) {
1528+ goto finish ;
1529+ }
1530+ #endif
1531+
1532+ off = 0 ;
15131533 if (duk_is_undefined (thr , 1 )) {
15141534 if (magic ) {
1515- p_cmp_start = p_cmp_start + DUK_HSTRING_GET_BYTELEN ( h ) - blen_search ;
1535+ off = ( duk_int_t ) blen_target - ( duk_int_t ) blen_search ;
15161536 } else {
1517- /* p_cmp_start already OK */
1537+ DUK_ASSERT ( off == 0 );
15181538 }
15191539 } else {
15201540 duk_int_t len ;
15211541 duk_int_t pos ;
15221542
15231543 DUK_ASSERT (DUK_HSTRING_MAX_BYTELEN <= DUK_INT_MAX );
1524- len = (duk_int_t ) DUK_HSTRING_GET_CHARLEN (h );
1544+ len = (duk_int_t ) DUK_HSTRING_GET_CHARLEN (h_target );
15251545 pos = duk_to_int_clamped (thr , 1 , 0 , len );
15261546 DUK_ASSERT (pos >= 0 && pos <= len );
15271547
1548+ off = (duk_int_t ) duk_heap_strcache_offset_char2byte (thr , h_target , (duk_uint_fast32_t ) pos );
15281549 if (magic ) {
1529- p_cmp_start -= blen_search ; /* Conceptually subtracted last, but do already here. */
1550+ off -= ( duk_int_t ) blen_search ;
15301551 }
1531- DUK_ASSERT ( pos >= 0 && pos <= len );
1532-
1533- p_cmp_start += duk_heap_strcache_offset_char2byte ( thr , h , ( duk_uint_fast32_t ) pos ) ;
1552+ }
1553+ if ( off < 0 || off > ( duk_int_t ) blen_target ) {
1554+ goto finish ;
15341555 }
15351556
15361557 /* The main comparison can be done using a memcmp() rather than
@@ -1540,16 +1561,18 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_startswith_endswith(duk_hthread *
15401561 * comparison range.
15411562 */
15421563
1543- result = 0 ;
1544- if (p_cmp_start >= DUK_HSTRING_GET_DATA (h ) &&
1545- (duk_size_t ) (p_cmp_start - (const duk_uint8_t * ) DUK_HSTRING_GET_DATA (h )) + blen_search <= DUK_HSTRING_GET_BYTELEN (h )) {
1546- if (duk_memcmp ((const void * ) p_cmp_start ,
1547- (const void * ) DUK_HSTRING_GET_DATA (h_search ),
1548- (size_t ) blen_search ) == 0 ) {
1564+ DUK_ASSERT (off >= 0 );
1565+ DUK_ASSERT ((duk_size_t ) off <= blen_target );
1566+ blen_left = blen_target - (duk_size_t ) off ;
1567+ if (blen_left >= blen_search ) {
1568+ const duk_uint8_t * p_cmp_start = (const duk_uint8_t * ) DUK_HSTRING_GET_DATA (h_target ) + off ;
1569+ const duk_uint8_t * p_search = (const duk_uint8_t * ) DUK_HSTRING_GET_DATA (h_search );
1570+ if (duk_memcmp_unsafe ((const void * ) p_cmp_start , (const void * ) p_search , (size_t ) blen_search ) == 0 ) {
15491571 result = 1 ;
15501572 }
15511573 }
15521574
1575+ finish :
15531576 duk_push_boolean (thr , result );
15541577 return 1 ;
15551578}
0 commit comments