Skip to content

Commit c4a006b

Browse files
committed
Saner numeric string handling for string offsets
1 parent b1f1f24 commit c4a006b

16 files changed

+106
-65
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 %sbug73792.php on line 4
15+
Warning: Illegal string offset '2bbb' in %sbug73792.php on line 4
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 %sbug76534.php:%d
13+
Fatal error: Uncaught Exception: Illegal string offset '2bar' in %sbug76534.php:%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 %sconst_dereference_002.php on line %d
14+
Warning: Illegal string offset '0foo' in %sconst_dereference_002.php on line %d
1515

16-
Warning: Illegal string offset 'bar' in %sconst_dereference_002.php on line %d
16+
Warning: Illegal string offset '0bar' in %sconst_dereference_002.php 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: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,19 @@ echo "Done\n";
3030
--EXPECTF--
3131
string(1) "l"
3232

33-
Warning: Illegal string offset '7.5' in %s on line 6
33+
Warning: String offset cast occurred in %s on line 6
3434
string(1) "l"
3535
string(1) "l"
3636

37-
Warning: Illegal string offset ' 7.5' in %s on line 8
37+
Warning: String offset cast occurred in %s on line 8
3838
string(1) "l"
3939
string(1) "l"
4040

41-
Warning: Illegal string offset ' 7.5 ' in %s on line 10
41+
Warning: String offset cast occurred in %s on line 10
4242
string(1) "l"
4343
string(1) "l"
4444

45-
Warning: Illegal string offset '7.5 ' in %s on line 12
45+
Warning: String offset cast occurred in %s on line 12
4646
string(1) "l"
4747

4848
Warning: Illegal string offset '7str' in %s on line 13

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 %soffset_assign.php on line %d
11+
Warning: Illegal string offset '2x' in %soffset_assign.php 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: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@ $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"]);
1317
var_dump($str["14.5"]);
1418
var_dump($str["15 and then some"]);
@@ -47,12 +51,10 @@ string(1) "S"
4751

4852
Warning: String offset cast occurred in %s on line %d
4953
string(1) "S"
50-
51-
Warning: Illegal string offset 'run away' in %s on line %d
52-
string(1) "S"
54+
Illegal offset type
5355
string(1) "c"
5456

55-
Warning: Illegal string offset '14.5' in %s on line %d
57+
Warning: String offset cast occurred in %s on line %d
5658
string(1) "o"
5759

5860
Warning: Illegal string offset '15 and then some' in %s on line %d

Zend/zend_execute.c

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1331,13 +1331,28 @@ static zend_never_inline zend_long zend_check_string_offset(zval *dim, int type
13311331
if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) {
13321332
switch(Z_TYPE_P(dim)) {
13331333
case IS_STRING:
1334-
if (IS_LONG == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, false)) {
1335-
break;
1334+
{
1335+
/* allow errors in string offset for BC reasons */
1336+
zend_uchar numeric_string_type = is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), &offset, NULL, true);
1337+
if (IS_LONG == numeric_string_type) {
1338+
/* emit Illegal string warning on leading numerical string */
1339+
if (0 == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, false)
1340+
&& type != BP_VAR_UNSET) {
1341+
zend_error(E_WARNING, "Illegal string offset '%s'", Z_STRVAL_P(dim));
1342+
}
1343+
return offset;
13361344
}
1337-
if (type != BP_VAR_UNSET) {
1338-
zend_error(E_WARNING, "Illegal string offset '%s'", Z_STRVAL_P(dim));
1345+
if (IS_DOUBLE == numeric_string_type) {
1346+
if (0 == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, false)) {
1347+
zend_error(E_WARNING, "Illegal string offset '%s'", Z_STRVAL_P(dim));
1348+
} else {
1349+
zend_error(E_WARNING, "String offset cast occurred");
1350+
}
1351+
break;
13391352
}
1353+
zend_illegal_offset();
13401354
break;
1355+
}
13411356
case IS_UNDEF:
13421357
ZVAL_UNDEFINED_OP2();
13431358
case IS_DOUBLE:
@@ -2259,17 +2274,33 @@ static zend_always_inline void zend_fetch_dimension_address_read(zval *result, z
22592274
try_string_offset:
22602275
if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) {
22612276
switch (Z_TYPE_P(dim)) {
2262-
/* case IS_LONG: */
22632277
case IS_STRING:
2264-
if (IS_LONG == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, false)) {
2278+
{
2279+
/* allow errors in string offset for BC reasons */
2280+
zend_uchar numeric_string_type = is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), &offset, NULL, true);
2281+
if (IS_LONG == numeric_string_type) {
2282+
/* emit Illegal string warning on leading numerical string */
2283+
if (0 == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, false)) {
2284+
zend_error(E_WARNING, "Illegal string offset '%s'", Z_STRVAL_P(dim));
2285+
}
2286+
goto out;
2287+
}
2288+
if (IS_DOUBLE == numeric_string_type) {
2289+
if (type != BP_VAR_IS &&
2290+
0 == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, false)) {
2291+
zend_error(E_WARNING, "Illegal string offset '%s'", Z_STRVAL_P(dim));
2292+
} else if (type != BP_VAR_IS) {
2293+
zend_error(E_WARNING, "String offset cast occurred");
2294+
}
22652295
break;
22662296
}
22672297
if (type == BP_VAR_IS) {
22682298
ZVAL_NULL(result);
22692299
return;
22702300
}
2271-
zend_error(E_WARNING, "Illegal string offset '%s'", Z_STRVAL_P(dim));
2301+
zend_illegal_offset();
22722302
break;
2303+
}
22732304
case IS_UNDEF:
22742305
ZVAL_UNDEFINED_OP2();
22752306
case IS_DOUBLE:
@@ -2292,6 +2323,7 @@ static zend_always_inline void zend_fetch_dimension_address_read(zval *result, z
22922323
} else {
22932324
offset = Z_LVAL_P(dim);
22942325
}
2326+
out:
22952327

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

tests/lang/bug19943.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ Bug #19943 (memleaks)
55
$ar = array();
66
for ($count = 0; $count < 10; $count++) {
77
$ar[$count] = "$count";
8-
@$ar[$count]['idx'] = "$count";
8+
@$ar[$count]['0idx'] = "$count";
99
}
1010

1111
for ($count = 0; $count < 10; $count++) {
12-
echo $ar[$count]." -- ".@$ar[$count]['idx']."\n";
12+
echo $ar[$count]." -- ".@$ar[$count]['0idx']."\n";
1313
}
1414
$a = "0123456789";
1515
$a[9] = $a[0];

tests/lang/bug29566.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ $var="This is a string";
77
$dummy="";
88
unset($dummy);
99

10-
foreach($var['nosuchkey'] as $v) {
10+
foreach($var['0.5nosuchkey'] as $v) {
1111
}
1212
?>
1313
--EXPECTF--
14-
Warning: Illegal string offset 'nosuchkey' in %sbug29566.php on line %d
14+
Warning: Illegal string offset '0.5nosuchkey' in %sbug29566.php on line %d
1515

1616
Warning: foreach() argument must be of type array|object, string given in %sbug29566.php on line %d

tests/strings/offsets_chaining_5.phpt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,20 @@ $array = array('expected_array' => "foobar");
66
var_dump(isset($array['expected_array']));
77
var_dump($array['expected_array']);
88
var_dump(isset($array['expected_array']['foo']));
9-
var_dump($array['expected_array']['foo']);
9+
var_dump($array['expected_array']['0foo']);
1010
var_dump(isset($array['expected_array']['foo']['bar']));
11-
var_dump($array['expected_array']['foo']['bar']);
11+
var_dump($array['expected_array']['0foo']['0bar']);
1212
?>
1313
--EXPECTF--
1414
bool(true)
1515
string(6) "foobar"
1616
bool(false)
1717

18-
Warning: Illegal string offset 'foo' in %soffsets_chaining_5.php on line %d
18+
Warning: Illegal string offset '0foo' in %soffsets_chaining_5.php on line %d
1919
string(1) "f"
2020
bool(false)
2121

22-
Warning: Illegal string offset 'foo' in %soffsets_chaining_5.php on line %d
22+
Warning: Illegal string offset '0foo' in %soffsets_chaining_5.php on line %d
2323

24-
Warning: Illegal string offset 'bar' in %soffsets_chaining_5.php on line %d
24+
Warning: Illegal string offset '0bar' in %soffsets_chaining_5.php on line %d
2525
string(1) "f"

tests/strings/offsets_general.phpt

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,19 @@ var_dump($string[0]);
99
var_dump($string[1]);
1010
var_dump(isset($string[0]));
1111
var_dump(isset($string[0][0]));
12-
var_dump($string["foo"]);
12+
try {
13+
var_dump($string["foo"]);
14+
} catch (\TypeError $e) {
15+
echo $e->getMessage() . \PHP_EOL;
16+
}
1317
var_dump(isset($string["foo"]["bar"]));
1418

1519
?>
16-
--EXPECTF--
20+
--EXPECT--
1721
string(1) "B"
1822
string(1) "f"
1923
string(1) "o"
2024
bool(true)
2125
bool(true)
22-
23-
Warning: Illegal string offset 'foo' in %s line %d
24-
string(1) "f"
26+
Illegal offset type
2527
bool(false)

0 commit comments

Comments
 (0)