php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #67824 Combination of array_map, exceptions, anonymous functions causes corruption
Submitted: 2014-08-12 00:29 UTC Modified: 2017-01-08 00:48 UTC
From: tristan dot veness at gmail dot com Assigned: nikic (profile)
Status: Closed Package: Scripting Engine problem
PHP Version: 5.5.15 OS: Any
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: tristan dot veness at gmail dot com
New email:
PHP Version: OS:

 

 [2014-08-12 00:29 UTC] 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)
  }
}


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2014-08-12 01:30 UTC] 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.
 [2016-07-14 11:29 UTC] dmitry@php.net
PHP-7 is not affected.
 [2017-01-08 00:48 UTC] nikic@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: nikic
 [2017-01-08 00:48 UTC] nikic@php.net
Closing as this bug has been fixed in PHP 7, while PHP 5.x is going out of active support.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Nov 30 03:01:29 2024 UTC