Skip to content

Commit bc8d067

Browse files
committed
Saner numeric string handling for string offsets
1 parent 1c22c6d commit bc8d067

19 files changed

+178
-143
lines changed

Zend/tests/bug24773.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Bug #24773 (unset() of integers treated as arrays causes a crash)
66
unset($array["lvl1"]["lvl2"]["b"]);
77
?>
88
--EXPECTF--
9-
Fatal error: Uncaught Error: Cannot use string offset as an array in %s:%d
9+
Fatal error: Uncaught TypeError: Illegal offset type in %s:%d
1010
Stack trace:
1111
#0 {main}
1212
thrown in %s on line %d

Zend/tests/bug31098.phpt

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,28 @@ var_dump(isset($a['b']));
1717

1818
$simpleString = "Bogus String Text";
1919
echo isset($simpleString->wrong)?"bug\n":"ok\n";
20-
echo isset($simpleString["wrong"])?"bug\n":"ok\n";
20+
try {
21+
echo isset($simpleString["wrong"])?"bug\n":"ok\n";
22+
} catch (\TypeError $e) {
23+
echo $e->getMessage() . \PHP_EOL;
24+
}
2125
echo isset($simpleString[-20])?"bug\n":"ok\n";
2226
echo isset($simpleString[0])?"ok\n":"bug\n";
2327
echo isset($simpleString["0"])?"ok\n":"bug\n";
2428
echo isset($simpleString["16"])?"ok\n":"bug\n";
2529
echo isset($simpleString["17"])?"bug\n":"ok\n";
2630
echo $simpleString->wrong === null?"ok\n":"bug\n";
27-
echo $simpleString["wrong"] === "B"?"ok\n":"bug\n";
31+
try {
32+
echo $simpleString["wrong"] === "B"?"ok\n":"bug\n";
33+
} catch (\TypeError $e) {
34+
echo $e->getMessage() . \PHP_EOL;
35+
}
2836
echo $simpleString["0"] === "B"?"ok\n":"bug\n";
29-
$simpleString["wrong"] = "f";
37+
try {
38+
$simpleString["wrong"] = "f";
39+
} catch (\TypeError $e) {
40+
echo $e->getMessage() . \PHP_EOL;
41+
}
3042
echo $simpleString["0"] === "f"?"ok\n":"bug\n";
3143
?>
3244
--EXPECTF--
@@ -46,10 +58,7 @@ ok
4658

4759
Warning: Attempt to read property "wrong" on string in %s on line %d
4860
ok
49-
50-
Warning: Illegal string offset "wrong" in %s on line %d
51-
ok
61+
Illegal offset type
5262
ok
53-
54-
Warning: Illegal string offset "wrong" in %s on line %d
63+
Illegal offset type
5564
ok

Zend/tests/bug53432.phpt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@ var_dump($str[-1] = 'a');
1616
var_dump($str);
1717

1818
$str = '';
19-
var_dump($str['foo'] = 'a');
19+
try {
20+
var_dump($str['foo'] = 'a');
21+
} catch (\TypeError $e) {
22+
echo $e->getMessage() . \PHP_EOL;
23+
}
2024
var_dump($str);
2125

2226
$str = '';
@@ -53,9 +57,7 @@ string(6) " a"
5357
Warning: Illegal string offset -1 in %s on line %d
5458
NULL
5559
string(0) ""
56-
57-
Warning: Illegal string offset "foo" in %s on line %d
58-
string(1) "a"
60+
Illegal offset type
5961
string(1) "a"
6062
Error: [] operator not supported for strings
6163
string(0) ""

Zend/tests/bug64578.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ Bug #64578 (debug_backtrace in set_error_handler corrupts zend heap: segfault)
55

66
set_error_handler(function($no, $err) { var_dump($err); });
77

8-
function x($s) { $s['a'] = 1; };
8+
function x($s) { $s['2a'] = 1; };
99
$y = '1';
1010
x($y);
1111
print_r($y);
1212
--EXPECT--
13-
string(25) "Illegal string offset "a""
13+
string(26) "Illegal string offset "2a""
1414
1

Zend/tests/bug73792.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ Bug #73792 (invalid foreach loop hangs script)
44
<?php
55
$a = 'aaa';
66

7-
foreach ($a['bbb'] as &$value) {
7+
foreach ($a['2bbb'] as &$value) {
88
echo 'loop';
99
}
1010

1111
unset($value);
1212
echo 'done';
1313
?>
1414
--EXPECTF--
15-
Warning: Illegal string offset "bbb" in %s on line %d
15+
Warning: Illegal string offset "2bbb" in %s on line %d
1616

1717
Fatal error: Uncaught Error: Cannot iterate on string offsets by reference in %sbug73792.php:4
1818
Stack trace:

Zend/tests/bug76534.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ set_error_handler(function ($severity, $message, $file, $line) {
77
});
88

99
$x = "foo";
10-
$y = &$x["bar"];
10+
$y = &$x["2bar"];
1111
?>
1212
--EXPECTF--
13-
Fatal error: Uncaught Exception: Illegal string offset "bar" in %s:%d
13+
Fatal error: Uncaught Exception: Illegal string offset "2bar" in %s:%d
1414
Stack trace:
1515
#0 %sbug76534.php(%d): {closure}(2, 'Illegal string ...', '%s', %d)
1616
#1 {main}

Zend/tests/const_dereference_002.phpt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ error_reporting(E_ALL);
66

77
var_dump("foobar"[3]);
88
var_dump("foobar"[2][0]);
9-
var_dump("foobar"["foo"]["bar"]);
9+
var_dump("foobar"["0foo"]["0bar"]);
1010
--EXPECTF--
1111
string(1) "b"
1212
string(1) "o"
1313

14-
Warning: Illegal string offset "foo" in %s on line %d
14+
Warning: Illegal string offset "0foo" in %s on line %d
1515

16-
Warning: Illegal string offset "bar" in %s on line %d
16+
Warning: Illegal string offset "0bar" in %s on line %d
1717
string(1) "f"

Zend/tests/indexing_001.phpt

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -75,19 +75,13 @@ array(1) {
7575
}
7676
}
7777

78-
Warning: Illegal string offset "foo" in %s on line %d
79-
8078
Warning: Array to string conversion in %s on line %d
81-
82-
Warning: Only the first byte will be assigned to the string offset in %s on line %d
83-
string(1) "A"
84-
85-
Warning: Illegal string offset "foo" in %s on line %d
79+
Illegal offset type
80+
string(0) ""
8681

8782
Warning: Array to string conversion in %s on line %d
88-
89-
Warning: Only the first byte will be assigned to the string offset in %s on line %d
90-
string(1) "A"
83+
Illegal offset type
84+
string(1) " "
9185
Cannot use a scalar value as an array
9286
float(0.1)
9387
array(1) {

Zend/tests/numeric_strings/string_offset.phpt

Lines changed: 43 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -5,74 +5,68 @@ Using different sorts of numerical strings as a string offset
55

66
$str = "The world is fun";
77

8-
var_dump($str["7"]);
9-
var_dump($str["7.5"]);
10-
var_dump($str[" 7"]);
11-
var_dump($str[" 7.5"]);
12-
var_dump($str[" 7 "]);
13-
var_dump($str[" 7.5 "]);
14-
var_dump($str["7 "]);
15-
var_dump($str["7.5 "]);
16-
var_dump($str["7str"]);
17-
var_dump($str["7.5str"]);
18-
var_dump($str[" 7str"]);
19-
var_dump($str[" 7.5str"]);
20-
var_dump($str[" 7 str"]);
21-
var_dump($str[" 7.5 str"]);
22-
var_dump($str["7 str"]);
23-
var_dump($str["7.5 str"]);
24-
var_dump($str["0xC"]);
25-
var_dump($str["0b10"]);
26-
var_dump($str["07"]);
8+
$keys = [
9+
"7",
10+
"7.5",
11+
" 7",
12+
" 7.5",
13+
" 7 ",
14+
" 7.5 ",
15+
"7 ",
16+
"7.5 ",
17+
"7str",
18+
"7.5str",
19+
" 7str",
20+
" 7.5str",
21+
" 7 str",
22+
" 7.5 str",
23+
"7 str",
24+
"7.5 str",
25+
"0xC",
26+
"0b10",
27+
"07",
28+
];
29+
30+
foreach ($keys as $key) {
31+
try {
32+
var_dump($str[$key]);
33+
} catch (\TypeError $e) {
34+
echo $e->getMessage() . \PHP_EOL;
35+
}
36+
}
2737

2838
echo "Done\n";
2939
?>
3040
--EXPECTF--
3141
string(1) "l"
32-
33-
Warning: Illegal string offset "7.5" in %s on line 6
34-
string(1) "l"
35-
string(1) "l"
36-
37-
Warning: Illegal string offset " 7.5" in %s on line 8
38-
string(1) "l"
39-
string(1) "l"
40-
41-
Warning: Illegal string offset " 7.5 " in %s on line 10
42-
string(1) "l"
42+
Illegal offset type
4343
string(1) "l"
44-
45-
Warning: Illegal string offset "7.5 " in %s on line 12
46-
string(1) "l"
47-
48-
Warning: Illegal string offset "7str" in %s on line 13
49-
string(1) "l"
50-
51-
Warning: Illegal string offset "7.5str" in %s on line 14
52-
string(1) "l"
53-
54-
Warning: Illegal string offset " 7str" in %s on line 15
44+
Illegal offset type
5545
string(1) "l"
56-
57-
Warning: Illegal string offset " 7.5str" in %s on line 16
46+
Illegal offset type
5847
string(1) "l"
48+
Illegal offset type
5949

60-
Warning: Illegal string offset " 7 str" in %s on line 17
50+
Warning: Illegal string offset "7str" in %s on line %d
6151
string(1) "l"
52+
Illegal offset type
6253

63-
Warning: Illegal string offset " 7.5 str" in %s on line 18
54+
Warning: Illegal string offset " 7str" in %s on line %d
6455
string(1) "l"
56+
Illegal offset type
6557

66-
Warning: Illegal string offset "7 str" in %s on line 19
58+
Warning: Illegal string offset " 7 str" in %s on line %d
6759
string(1) "l"
60+
Illegal offset type
6861

69-
Warning: Illegal string offset "7.5 str" in %s on line 20
62+
Warning: Illegal string offset "7 str" in %s on line %d
7063
string(1) "l"
64+
Illegal offset type
7165

72-
Warning: Illegal string offset "0xC" in %s on line 21
66+
Warning: Illegal string offset "0xC" in %s on line %d
7367
string(1) "T"
7468

75-
Warning: Illegal string offset "0b10" in %s on line 22
69+
Warning: Illegal string offset "0b10" in %s on line %d
7670
string(1) "T"
7771
string(1) "l"
7872
Done

Zend/tests/offset_assign.phpt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
--TEST--
2-
Crash on $x['x']['y'] += 1 when $x is string
2+
Crash on $x['2x']['y'] += 1 when $x is string
33
--FILE--
44
<?php
55
$x = "a";
6-
$x['x']['y'] += 1;
6+
$x['2x']['y'] += 1;
77

88
echo "Done\n";
99
?>
1010
--EXPECTF--
11-
Warning: Illegal string offset "x" in %s on line %d
11+
Warning: Illegal string offset "2x" in %s on line %d
1212

1313
Fatal error: Uncaught Error: Cannot use string offset as an array in %soffset_assign.php:%d
1414
Stack trace:

Zend/tests/offset_string.phpt

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,17 @@ $str = "Sitting on a corner all alone, staring from the bottom of his soul";
88
var_dump($str[1]);
99
var_dump($str[0.0836]);
1010
var_dump($str[NULL]);
11-
var_dump($str["run away"]);
11+
try {
12+
var_dump($str["run away"]);
13+
} catch (\TypeError $e) {
14+
echo $e->getMessage() . \PHP_EOL;
15+
}
1216
var_dump($str["13"]);
13-
var_dump($str["14.5"]);
17+
try {
18+
var_dump($str["14.5"]);
19+
} catch (\TypeError $e) {
20+
echo $e->getMessage() . \PHP_EOL;
21+
}
1422
var_dump($str["15 and then some"]);
1523

1624
var_dump($str[TRUE]);
@@ -47,13 +55,9 @@ string(1) "S"
4755

4856
Warning: String offset cast occurred in %s on line %d
4957
string(1) "S"
50-
51-
Warning: Illegal string offset "run away" in %s on line %d
52-
string(1) "S"
58+
Illegal offset type
5359
string(1) "c"
54-
55-
Warning: Illegal string offset "14.5" in %s on line %d
56-
string(1) "o"
60+
Illegal offset type
5761

5862
Warning: Illegal string offset "15 and then some" in %s on line %d
5963
string(1) "r"

Zend/zend_execute.c

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1328,13 +1328,19 @@ static zend_never_inline zend_long zend_check_string_offset(zval *dim, int type
13281328
if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) {
13291329
switch(Z_TYPE_P(dim)) {
13301330
case IS_STRING:
1331-
if (IS_LONG == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, false)) {
1332-
break;
1333-
}
1334-
if (type != BP_VAR_UNSET) {
1335-
zend_error(E_WARNING, "Illegal string offset \"%s\"", Z_STRVAL_P(dim));
1331+
{
1332+
/* allow errors in string offset for BC reasons */
1333+
if (IS_LONG == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), &offset, NULL, true)) {
1334+
/* emit Illegal string warning on leading numerical string */
1335+
if (0 == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, false)
1336+
&& type != BP_VAR_UNSET) {
1337+
zend_error(E_WARNING, "Illegal string offset \"%s\"", Z_STRVAL_P(dim));
1338+
}
1339+
return offset;
13361340
}
1341+
zend_illegal_offset();
13371342
break;
1343+
}
13381344
case IS_UNDEF:
13391345
ZVAL_UNDEFINED_OP2();
13401346
case IS_DOUBLE:
@@ -2313,17 +2319,23 @@ static zend_always_inline void zend_fetch_dimension_address_read(zval *result, z
23132319
try_string_offset:
23142320
if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) {
23152321
switch (Z_TYPE_P(dim)) {
2316-
/* case IS_LONG: */
23172322
case IS_STRING:
2318-
if (IS_LONG == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, false)) {
2319-
break;
2323+
{
2324+
/* allow errors in string offset for BC reasons */
2325+
if (IS_LONG == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), &offset, NULL, true)) {
2326+
/* emit Illegal string warning on leading numerical string */
2327+
if (0 == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, false)) {
2328+
zend_error(E_WARNING, "Illegal string offset \"%s\"", Z_STRVAL_P(dim));
2329+
}
2330+
goto out;
23202331
}
23212332
if (type == BP_VAR_IS) {
23222333
ZVAL_NULL(result);
23232334
return;
23242335
}
2325-
zend_error(E_WARNING, "Illegal string offset \"%s\"", Z_STRVAL_P(dim));
2336+
zend_illegal_offset();
23262337
break;
2338+
}
23272339
case IS_UNDEF:
23282340
ZVAL_UNDEFINED_OP2();
23292341
case IS_DOUBLE:
@@ -2346,6 +2358,7 @@ static zend_always_inline void zend_fetch_dimension_address_read(zval *result, z
23462358
} else {
23472359
offset = Z_LVAL_P(dim);
23482360
}
2361+
out:
23492362

23502363
if (UNEXPECTED(Z_STRLEN_P(container) < ((offset < 0) ? -(size_t)offset : ((size_t)offset + 1)))) {
23512364
if (type != BP_VAR_IS) {

0 commit comments

Comments
 (0)