diff options
author | Francois Laupretre <francois@php.net> | 2015-07-21 22:16:08 +0200 |
---|---|---|
committer | Nikita Popov <nikic@php.net> | 2016-03-09 14:41:37 +0100 |
commit | 370b7039e4ba1f54d8051779c04c1f8d8e16837b (patch) | |
tree | 047ee0888ea1a15380749d8ac8d82138ee8b5159 | |
parent | aa2cf3a4f20ca3ca2685db1fa86d8e242a413225 (diff) | |
download | php-git-370b7039e4ba1f54d8051779c04c1f8d8e16837b.tar.gz |
Add support for negative string offsets (syntax)
-rw-r--r-- | Zend/tests/bug29883.phpt | 2 | ||||
-rw-r--r-- | Zend/tests/bug31098.phpt | 2 | ||||
-rw-r--r-- | Zend/tests/empty_str_offset.phpt | 12 | ||||
-rw-r--r-- | Zend/tests/isset_str_offset.phpt | 6 | ||||
-rw-r--r-- | Zend/tests/str_offset_001.phpt | 97 | ||||
-rw-r--r-- | Zend/tests/str_offset_003.phpt | 37 | ||||
-rw-r--r-- | Zend/tests/str_offset_004.phpt | 49 | ||||
-rw-r--r-- | Zend/zend_execute.c | 17 | ||||
-rw-r--r-- | Zend/zend_vm_def.h | 3 | ||||
-rw-r--r-- | Zend/zend_vm_execute.h | 36 |
10 files changed, 204 insertions, 57 deletions
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-- <?php $x = "bug"; -var_dump(isset($x[-1])); +var_dump(isset($x[-10])); var_dump(isset($x["1"])); echo $x["1"]."\n"; ?> 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--
-<?php
-function foo($x) {
- var_dump($x);
-}
-
-$str = "abc";
-var_dump($str[-1]);
-var_dump($str[0]);
-var_dump($str[1]);
-var_dump($str[2]);
-var_dump($str[3]);
-var_dump($str[1][0]);
-var_dump($str[2][1]);
-
-foo($str[-1]);
-foo($str[0]);
-foo($str[1]);
-foo($str[2]);
-foo($str[3]);
-foo($str[1][0]);
-foo($str[2][1]);
-?>
---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-- +<?php +// Test positive or null string offsets + +function foo($x) { + var_dump($x); +} + +$str = "abc"; +var_dump($str[0]); +var_dump($str[1]); +var_dump($str[2]); +var_dump($str[3]); +var_dump($str[1][0]); +var_dump($str[2][1]); + +foo($str[0]); +foo($str[1]); +foo($str[2]); +foo($str[3]); +foo($str[1][0]); +foo($str[2][1]); +?> +--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-- +<?php +// Test negative string offsets + +function foo($x) { + var_dump($x); +} + +$str = "abcdef"; +var_dump($str[-10]); +var_dump($str[-3]); +var_dump($str[2][-2]); +var_dump($str[2][-1]); + +foo($str[-10]); +foo($str[-3]); +foo($str[2][-2]); +foo($str[2][-1]); +?> +--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-- +<?php +// Test assignments using (positive and negative) string offsets + +$str = "abcdefghijklmno"; +$i = 3; +$j = -4; + +$str{2} = 'C'; +var_dump($str); + +$str{$i} = 'Z'; +var_dump($str); + +$str{-5} = 'P'; +var_dump($str); + +$str{$j} = 'Q'; +var_dump($str); + +$str{-20} = 'Y'; +var_dump($str); + +$str{-strlen($str)} = strtoupper($str{0}); /* An exotic ucfirst() ;) */ +var_dump($str); + +$str{20} = 'N'; +var_dump($str); + +$str{-2} = 'UFO'; +var_dump($str); + +$str{-$i} = $str{$j*2}; +var_dump($str); +?> +--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; |