Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Fixed bug #63217
Don't automatically convert literal string keys to integers on array access, as we may be dealing with an ArrayAccess object, rather than a plain array.
- Loading branch information
Showing
with
271 additions
and 152 deletions.
- +2 −0 NEWS
- +6 −0 UPGRADING
- +11 −3 Zend/tests/bug29883.phpt
- +1 −1 Zend/tests/bug55135.phpt
- +123 −0 Zend/tests/bug63217.phpt
- +21 −5 Zend/tests/empty_str_offset.phpt
- +22 −4 Zend/tests/isset_str_offset.phpt
- +0 −1 Zend/zend_compile.c
- +2 −4 Zend/zend_execute.c
- +4 −8 Zend/zend_vm_def.h
- +30 −60 Zend/zend_vm_execute.h
- +49 −54 ext/opcache/Optimizer/zend_inference.c
- +0 −12 ext/opcache/Optimizer/zend_optimizer.c
@@ -0,0 +1,123 @@ | ||
--TEST-- | ||
Bug #63217 (Constant numeric strings become integers when used as ArrayAccess offset) | ||
--INI-- | ||
opcache.enable_cli=1 | ||
opcache.enable=1 | ||
opcache.optimization_level=-1 | ||
--FILE-- | ||
<?php | ||
class Test implements ArrayAccess { | ||
public function offsetExists($offset) { | ||
echo "offsetExists given "; | ||
var_dump($offset); | ||
} | ||
public function offsetUnset($offset) { | ||
echo "offsetUnset given "; | ||
var_dump($offset); | ||
} | ||
public function offsetSet($offset, $value) { | ||
echo "offsetSet given "; | ||
var_dump($offset); | ||
} | ||
public function offsetGet($offset) { | ||
echo "offsetGet given "; | ||
var_dump($offset); | ||
} | ||
} | ||
|
||
$test = new Test; | ||
|
||
/* These should all produce string(...) "..." output and not int(...) */ | ||
isset($test['0']); | ||
isset($test['123']); | ||
unset($test['0']); | ||
unset($test['123']); | ||
$test['0'] = true; | ||
$test['123'] = true; | ||
$foo = $test['0']; | ||
$foo = $test['123']; | ||
|
||
/* These caused the same bug, but in opcache rather than the compiler */ | ||
isset($test[(string)'0']); | ||
isset($test[(string)'123']); | ||
unset($test[(string)'0']); | ||
unset($test[(string)'123']); | ||
$test[(string)'0'] = true; | ||
$test[(string)'123'] = true; | ||
$foo = $test[(string)'0']; | ||
$foo = $test[(string)'123']; | ||
|
||
/** | ||
* @see https://github.com/php/php-src/pull/2607#issuecomment-313781748 | ||
*/ | ||
function test(): string { | ||
$array["10"] = 42; | ||
foreach ($array as $key => $value) { | ||
return $key; | ||
} | ||
} | ||
|
||
var_dump(test()); | ||
|
||
/** | ||
* Make sure we don't break arrays. | ||
*/ | ||
$array = []; | ||
|
||
$key = '123'; | ||
|
||
$array[$key] = 1; | ||
$array['321'] = 2; | ||
$array['abc'] = 3; | ||
|
||
var_dump($array); | ||
|
||
/** | ||
* Make sure that we haven't broken ArrayObject | ||
*/ | ||
$ao = new ArrayObject(); | ||
|
||
$key = '123'; | ||
|
||
$ao = []; | ||
$ao[$key] = 1; | ||
$ao['321'] = 2; | ||
$ao['abc'] = 3; | ||
|
||
var_dump($ao); | ||
|
||
?> | ||
--EXPECT-- | ||
offsetExists given string(1) "0" | ||
offsetExists given string(3) "123" | ||
offsetUnset given string(1) "0" | ||
offsetUnset given string(3) "123" | ||
offsetSet given string(1) "0" | ||
offsetSet given string(3) "123" | ||
offsetGet given string(1) "0" | ||
offsetGet given string(3) "123" | ||
offsetExists given string(1) "0" | ||
offsetExists given string(3) "123" | ||
offsetUnset given string(1) "0" | ||
offsetUnset given string(3) "123" | ||
offsetSet given string(1) "0" | ||
offsetSet given string(3) "123" | ||
offsetGet given string(1) "0" | ||
offsetGet given string(3) "123" | ||
string(2) "10" | ||
array(3) { | ||
[123]=> | ||
int(1) | ||
[321]=> | ||
int(2) | ||
["abc"]=> | ||
int(3) | ||
} | ||
array(3) { | ||
[123]=> | ||
int(1) | ||
[321]=> | ||
int(2) | ||
["abc"]=> | ||
int(3) | ||
} |
Oops, something went wrong.