From: Francois Laupretre Date: Tue, 21 Jul 2015 20:16:08 +0000 (+0200) Subject: Add support for negative string offsets (syntax) X-Git-Tag: php-7.1.0alpha1~516 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=370b7039e4ba1f54d8051779c04c1f8d8e16837b;p=php Add support for negative string offsets (syntax) --- diff --git a/Zend/tests/bug29883.phpt b/Zend/tests/bug29883.phpt index c92f147ff7..b6ad99aeaf 100644 --- a/Zend/tests/bug29883.phpt +++ b/Zend/tests/bug29883.phpt @@ -3,7 +3,7 @@ Bug #29883 (isset gives invalid values on strings) --FILE-- diff --git a/Zend/tests/bug31098.phpt b/Zend/tests/bug31098.phpt index 23cec9bbf4..31823a1aa5 100644 --- a/Zend/tests/bug31098.phpt +++ b/Zend/tests/bug31098.phpt @@ -18,7 +18,7 @@ var_dump(isset($a['b'])); $simpleString = "Bogus String Text"; echo isset($simpleString->wrong)?"bug\n":"ok\n"; echo isset($simpleString["wrong"])?"bug\n":"ok\n"; -echo isset($simpleString[-1])?"bug\n":"ok\n"; +echo isset($simpleString[-20])?"bug\n":"ok\n"; echo isset($simpleString[0])?"ok\n":"bug\n"; echo isset($simpleString["0"])?"ok\n":"bug\n"; echo isset($simpleString["16"])?"ok\n":"bug\n"; diff --git a/Zend/tests/empty_str_offset.phpt b/Zend/tests/empty_str_offset.phpt index 486c052dc4..49e175dd21 100644 --- a/Zend/tests/empty_str_offset.phpt +++ b/Zend/tests/empty_str_offset.phpt @@ -8,6 +8,8 @@ print "- empty ---\n"; $str = "test0123"; var_dump(empty($str[-1])); +var_dump(empty($str[-10])); +var_dump(empty($str[-4])); // 0 var_dump(empty($str[0])); var_dump(empty($str[1])); var_dump(empty($str[4])); // 0 @@ -17,6 +19,8 @@ var_dump(empty($str[10000])); // non-numeric offsets print "- string ---\n"; var_dump(empty($str['-1'])); +var_dump(empty($str['-10'])); +var_dump(empty($str['-4'])); // 0 var_dump(empty($str['0'])); var_dump(empty($str['1'])); var_dump(empty($str['4'])); // 0 @@ -31,6 +35,8 @@ print "- null ---\n"; var_dump(empty($str[null])); print "- double ---\n"; var_dump(empty($str[-1.1])); +var_dump(empty($str[-10.5])); +var_dump(empty($str[-4.1])); var_dump(empty($str[-0.8])); var_dump(empty($str[-0.1])); var_dump(empty($str[0.2])); @@ -50,6 +56,8 @@ print "done\n"; ?> --EXPECTF-- - empty --- +bool(false) +bool(true) bool(true) bool(false) bool(false) @@ -58,6 +66,8 @@ bool(false) bool(true) bool(true) - string --- +bool(false) +bool(true) bool(true) bool(false) bool(false) @@ -72,6 +82,8 @@ bool(true) - null --- bool(false) - double --- +bool(false) +bool(true) bool(true) bool(false) bool(false) diff --git a/Zend/tests/isset_str_offset.phpt b/Zend/tests/isset_str_offset.phpt index 7a9164a381..d693f80a52 100644 --- a/Zend/tests/isset_str_offset.phpt +++ b/Zend/tests/isset_str_offset.phpt @@ -8,6 +8,7 @@ print "- isset ---\n"; $str = "test0123"; var_dump(isset($str[-1])); +var_dump(isset($str[-10])); var_dump(isset($str[0])); var_dump(isset($str[1])); var_dump(isset($str[4])); // 0 @@ -17,6 +18,7 @@ var_dump(isset($str[10000])); // non-numeric offsets print "- string ---\n"; var_dump(isset($str['-1'])); +var_dump(isset($str['-10'])); var_dump(isset($str['0'])); var_dump(isset($str['1'])); var_dump(isset($str['4'])); // 0 @@ -31,6 +33,7 @@ print "- null ---\n"; var_dump(isset($str[null])); print "- double ---\n"; var_dump(isset($str[-1.1])); +var_dump(isset($str[-10.5])); var_dump(isset($str[-0.8])); var_dump(isset($str[-0.1])); var_dump(isset($str[0.2])); @@ -50,6 +53,7 @@ print "done\n"; ?> --EXPECTF-- - isset --- +bool(true) bool(false) bool(true) bool(true) @@ -58,6 +62,7 @@ bool(true) bool(false) bool(false) - string --- +bool(true) bool(false) bool(true) bool(true) @@ -72,6 +77,7 @@ bool(false) - null --- bool(true) - double --- +bool(true) bool(false) bool(true) bool(true) diff --git a/Zend/tests/str_offset_001.phpt b/Zend/tests/str_offset_001.phpt index 8a6b91b49a..3317674857 100644 --- a/Zend/tests/str_offset_001.phpt +++ b/Zend/tests/str_offset_001.phpt @@ -1,51 +1,46 @@ ---TEST-- -string offset 001 ---FILE-- - ---EXPECTF-- -Notice: Uninitialized string offset: -1 in %sstr_offset_001.php on line %d -string(0) "" -string(1) "a" -string(1) "b" -string(1) "c" - -Notice: Uninitialized string offset: 3 in %sstr_offset_001.php on line %d -string(0) "" -string(1) "b" - -Notice: Uninitialized string offset: 1 in %sstr_offset_001.php on line %d -string(0) "" - -Notice: Uninitialized string offset: -1 in %sstr_offset_001.php on line %d -string(0) "" -string(1) "a" -string(1) "b" -string(1) "c" - -Notice: Uninitialized string offset: 3 in %sstr_offset_001.php on line %d -string(0) "" -string(1) "b" - -Notice: Uninitialized string offset: 1 in %sstr_offset_001.php on line %d -string(0) "" +--TEST-- +string offset 001 +--FILE-- + +--EXPECTF-- +string(1) "a" +string(1) "b" +string(1) "c" + +Notice: Uninitialized string offset: 3 in %sstr_offset_001.php on line %d +string(0) "" +string(1) "b" + +Notice: Uninitialized string offset: 1 in %sstr_offset_001.php on line %d +string(0) "" +string(1) "a" +string(1) "b" +string(1) "c" + +Notice: Uninitialized string offset: 3 in %sstr_offset_001.php on line %d +string(0) "" +string(1) "b" + +Notice: Uninitialized string offset: 1 in %sstr_offset_001.php on line %d +string(0) "" diff --git a/Zend/tests/str_offset_003.phpt b/Zend/tests/str_offset_003.phpt new file mode 100644 index 0000000000..e357ac0c01 --- /dev/null +++ b/Zend/tests/str_offset_003.phpt @@ -0,0 +1,37 @@ +--TEST-- +string offset 003 +--FILE-- + +--EXPECTF-- +Notice: Uninitialized string offset: -10 in %sstr_offset_003.php on line %d +string(0) "" +string(1) "d" + +Notice: Uninitialized string offset: -2 in %sstr_offset_003.php on line %d +string(0) "" +string(1) "c" + +Notice: Uninitialized string offset: -10 in %sstr_offset_003.php on line %d +string(0) "" +string(1) "d" + +Notice: Uninitialized string offset: -2 in %sstr_offset_003.php on line %d +string(0) "" +string(1) "c" diff --git a/Zend/tests/str_offset_004.phpt b/Zend/tests/str_offset_004.phpt new file mode 100644 index 0000000000..c8ce607535 --- /dev/null +++ b/Zend/tests/str_offset_004.phpt @@ -0,0 +1,49 @@ +--TEST-- +string offset 004 +--FILE-- + +--EXPECTF-- +string(15) "abCdefghijklmno" +string(15) "abCZefghijklmno" +string(15) "abCZefghijPlmno" +string(15) "abCZefghijPQmno" + +Warning: Illegal string offset: -20 in %sstr_offset_004.php on line %d +string(15) "abCZefghijPQmno" +string(15) "AbCZefghijPQmno" +string(21) "AbCZefghijPQmno N" +string(21) "AbCZefghijPQmno UN" +string(21) "AbCZefghijPQmno nUN" diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index de5875fdba..3918ddd7ae 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1172,7 +1172,7 @@ static void zend_assign_to_string_offset(zval *str, zend_long offset, zval *valu zend_uchar c; size_t string_len; - if (offset < 0) { + if (offset < (zend_long)(-Z_STRLEN_P(str))) { /* Error on negative offset */ zend_error(E_WARNING, "Illegal string offset: " ZEND_LONG_FMT, offset); zend_string_release(Z_STR_P(str)); @@ -1204,6 +1204,10 @@ static void zend_assign_to_string_offset(zval *str, zend_long offset, zval *valu return; } + if (offset < 0) { /* Handle negative offset */ + offset += (zend_long)Z_STRLEN_P(str); + } + old_str = Z_STR_P(str); if ((size_t)offset >= Z_STRLEN_P(str)) { /* Extend string if needed */ @@ -1849,7 +1853,7 @@ try_string_offset: offset = Z_LVAL_P(dim); } - if (UNEXPECTED(offset < 0) || UNEXPECTED(Z_STRLEN_P(container) <= (size_t)offset)) { + if (UNEXPECTED(Z_STRLEN_P(container) < (size_t)((offset < 0) ? -offset : (offset + 1)))) { if (type != BP_VAR_IS) { zend_error(E_NOTICE, "Uninitialized string offset: %pd", offset); ZVAL_EMPTY_STRING(result); @@ -1857,12 +1861,17 @@ try_string_offset: ZVAL_NULL(result); } } else { - zend_uchar c = (zend_uchar)Z_STRVAL_P(container)[offset]; + zend_uchar c; + zend_long real_offset; + + real_offset = (UNEXPECTED(offset < 0)) /* Handle negative offset */ + ? (zend_long)Z_STRLEN_P(container) + offset : offset; + c = (zend_uchar)Z_STRVAL_P(container)[real_offset]; if (CG(one_char_string)[c]) { ZVAL_INTERNED_STR(result, CG(one_char_string)[c]); } else { - ZVAL_NEW_STR(result, zend_string_init(Z_STRVAL_P(container) + offset, 1, 0)); + ZVAL_NEW_STR(result, zend_string_init(Z_STRVAL_P(container) + real_offset, 1, 0)); } } } else if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index de67318bed..627c2c1886 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -6742,6 +6742,9 @@ ZEND_VM_C_LABEL(num_index_prop): if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) { lval = Z_LVAL_P(offset); ZEND_VM_C_LABEL(isset_str_offset): + if (UNEXPECTED(lval < 0)) { /* Handle negative offset */ + lval += (zend_long)Z_STRLEN_P(container); + } if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) { if (opline->extended_value & ZEND_ISSET) { result = 1; diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 40d75a7d27..dea44311af 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -6671,6 +6671,9 @@ num_index_prop: if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) { lval = Z_LVAL_P(offset); isset_str_offset: + if (UNEXPECTED(lval < 0)) { /* Handle negative offset */ + lval += (zend_long)Z_STRLEN_P(container); + } if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) { if (opline->extended_value & ZEND_ISSET) { result = 1; @@ -10200,6 +10203,9 @@ num_index_prop: if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) { lval = Z_LVAL_P(offset); isset_str_offset: + if (UNEXPECTED(lval < 0)) { /* Handle negative offset */ + lval += (zend_long)Z_STRLEN_P(container); + } if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) { if (opline->extended_value & ZEND_ISSET) { result = 1; @@ -11952,6 +11958,9 @@ num_index_prop: if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) { lval = Z_LVAL_P(offset); isset_str_offset: + if (UNEXPECTED(lval < 0)) { /* Handle negative offset */ + lval += (zend_long)Z_STRLEN_P(container); + } if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) { if (opline->extended_value & ZEND_ISSET) { result = 1; @@ -28296,6 +28305,9 @@ num_index_prop: if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) { lval = Z_LVAL_P(offset); isset_str_offset: + if (UNEXPECTED(lval < 0)) { /* Handle negative offset */ + lval += (zend_long)Z_STRLEN_P(container); + } if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) { if (opline->extended_value & ZEND_ISSET) { result = 1; @@ -31467,6 +31479,9 @@ num_index_prop: if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) { lval = Z_LVAL_P(offset); isset_str_offset: + if (UNEXPECTED(lval < 0)) { /* Handle negative offset */ + lval += (zend_long)Z_STRLEN_P(container); + } if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) { if (opline->extended_value & ZEND_ISSET) { result = 1; @@ -33711,6 +33726,9 @@ num_index_prop: if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) { lval = Z_LVAL_P(offset); isset_str_offset: + if (UNEXPECTED(lval < 0)) { /* Handle negative offset */ + lval += (zend_long)Z_STRLEN_P(container); + } if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) { if (opline->extended_value & ZEND_ISSET) { result = 1; @@ -39195,6 +39213,9 @@ num_index_prop: if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) { lval = Z_LVAL_P(offset); isset_str_offset: + if (UNEXPECTED(lval < 0)) { /* Handle negative offset */ + lval += (zend_long)Z_STRLEN_P(container); + } if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) { if (opline->extended_value & ZEND_ISSET) { result = 1; @@ -45424,6 +45445,9 @@ num_index_prop: if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) { lval = Z_LVAL_P(offset); isset_str_offset: + if (UNEXPECTED(lval < 0)) { /* Handle negative offset */ + lval += (zend_long)Z_STRLEN_P(container); + } if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) { if (opline->extended_value & ZEND_ISSET) { result = 1; @@ -48849,6 +48873,9 @@ num_index_prop: if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) { lval = Z_LVAL_P(offset); isset_str_offset: + if (UNEXPECTED(lval < 0)) { /* Handle negative offset */ + lval += (zend_long)Z_STRLEN_P(container); + } if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) { if (opline->extended_value & ZEND_ISSET) { result = 1; @@ -50895,6 +50922,9 @@ num_index_prop: if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) { lval = Z_LVAL_P(offset); isset_str_offset: + if (UNEXPECTED(lval < 0)) { /* Handle negative offset */ + lval += (zend_long)Z_STRLEN_P(container); + } if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) { if (opline->extended_value & ZEND_ISSET) { result = 1; @@ -52987,6 +53017,9 @@ num_index_prop: if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) { lval = Z_LVAL_P(offset); isset_str_offset: + if (UNEXPECTED(lval < 0)) { /* Handle negative offset */ + lval += (zend_long)Z_STRLEN_P(container); + } if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) { if (opline->extended_value & ZEND_ISSET) { result = 1; @@ -54126,6 +54159,9 @@ num_index_prop: if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) { lval = Z_LVAL_P(offset); isset_str_offset: + if (UNEXPECTED(lval < 0)) { /* Handle negative offset */ + lval += (zend_long)Z_STRLEN_P(container); + } if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) { if (opline->extended_value & ZEND_ISSET) { result = 1;