Bug #67824 [Opn]: Combination of array_map, exceptions, anonymous functions causes corruption

From: Date: Thu, 14 Jul 2016 11:29:45 +0000
Subject: Bug #67824 [Opn]: Combination of array_map, exceptions, anonymous functions causes corruption
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-202315@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=67824&edit=1 ID: 67824 Updated by: dmitry@php.net Reported by: tristan dot veness at gmail dot com Summary: Combination of array_map, exceptions, anonymous functions causes corruption Status: Open Type: Bug Package: Scripting Engine problem Operating System: Any PHP Version: 5.5.15 Block user comment: N Private report: N New Comment: PHP-7 is not affected. Previous Comments: ------------------------------------------------------------------------ [2014-08-12 01:30:40] requinix@php.net See also bug #67807, which is very likely the same root cause exposed through a different mechanism. Implying this is also potentially NAB. ------------------------------------------------------------------------ [2014-08-12 00:29:53] tristan dot veness at gmail dot com 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 this bug report at https://bugs.php.net/bug.php?id=67824&edit=1

« previous php.bugs (#202315) next »