Bug #67824 [NEW]: Combination of array_map, exceptions, anonymous functions causes corruption
| From: | tristan dot veness at gmail dot com | Date: | Tue, 12 Aug 2014 00:29:54 +0000 |
| Subject: | Bug #67824 [NEW]: Combination of array_map, exceptions, anonymous functions causes corruption | ||
| Groups: | php.bugs | ||
| Request: | Send a blank email to php-bugs+get-187085@lists.php.net to get a copy of this message | ||
From: tristan dot veness at gmail dot com
Operating system: Any
PHP version: 5.5.15
Package: Scripting Engine problem
Bug Type: Bug
Bug description:Combination of array_map, exceptions, anonymous functions causes corruption
Description:
------------
When using array_map with an anonymous function that throws an exception
- and then manipulating a copy of the stack trace, the original array
passed to array_map becomes corrupted.
This is a fairly obscure edge case, but I managed to run into it within
the framework I'm currently working with.
Apologies for the long code sample, I have had alot of difficulty
isolating the issue.
Test script:
---------------
<?php
$some_objects = [
new SomeClass(1), new SomeClass(2),
new SomeClass(3), new SomeClass(4),
];
$func = function(SomeClass $x) {
$x->some_function();
return $x;
};
array_walk($some_objects, $func);
var_dump($some_objects);
$mangled_result = array_map($func, $some_objects);
var_dump($mangled_result);
class SomeClass {
private $number;
public function __construct($number) {
$this->number = $number;
}
public function some_function() {
try {
throw new Exception();
}
catch (Exception $e) {
MANGLE_SOMEHOW($e->getTrace());
}
}
}
function MANGLE_SOMEHOW($trace) {
foreach ($trace as $i => $frame) {
if (isset($frame['args'])) {
foreach ($frame['args'] as $arg_index =>
$arg_value) {
// And here I was thinking this was a
'copy'???
$frame['args'][$arg_index] =
$arg_value;
}
}
}
}
?>
Expected result:
----------------
array(4) {
[0]=>
object(SomeClass)#1 (1) {
["number":"SomeClass":private]=>
int(1)
}
[1]=>
object(SomeClass)#2 (1) {
["number":"SomeClass":private]=>
int(2)
}
[2]=>
object(SomeClass)#3 (1) {
["number":"SomeClass":private]=>
int(3)
}
[3]=>
object(SomeClass)#4 (1) {
["number":"SomeClass":private]=>
int(4)
}
}
array(4) {
[0]=>
object(SomeClass)#1 (1) {
["number":"SomeClass":private]=>
int(1)
}
[1]=>
object(SomeClass)#2 (1) {
["number":"SomeClass":private]=>
int(2)
}
[2]=>
object(SomeClass)#3 (1) {
["number":"SomeClass":private]=>
int(3)
}
[3]=>
object(SomeClass)#4 (1) {
["number":"SomeClass":private]=>
int(4)
}
}
Actual result:
--------------
array(4) {
[0]=>
object(SomeClass)#1 (1) {
["number":"SomeClass":private]=>
int(1)
}
[1]=>
object(SomeClass)#2 (1) {
["number":"SomeClass":private]=>
int(2)
}
[2]=>
object(SomeClass)#3 (1) {
["number":"SomeClass":private]=>
int(3)
}
[3]=>
object(SomeClass)#4 (1) {
["number":"SomeClass":private]=>
int(4)
}
}
array(3) {
[0]=>
object(SomeClass)#1 (1) {
["number":"SomeClass":private]=>
int(1)
}
[140627626761080]=>
object(SomeClass)#2 (1) {
["number":"SomeClass":private]=>
int(2)
}
[140627626759920]=>
object(SomeClass)#2 (1) {
["number":"SomeClass":private]=>
int(2)
}
}
--
Edit bug report at https://bugs.php.net/bug.php?id=67824&edit=1
--