php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #72229 Wrong reference when serialize/unserialize an object
Submitted: 2016-05-17 08:22 UTC Modified: -
From: email at rodrigo-supper dot de Assigned:
Status: Closed Package: *General Issues
PHP Version: 7.0.6 OS: Ubuntu 14.04; Windows 7; ...
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: email at rodrigo-supper dot de
New email:
PHP Version: OS:

 

 [2016-05-17 08:22 UTC] email at rodrigo-supper dot de
Description:
------------
The Bug concerns serialization of an object: in certain cases a "real" reference (with a '&' like &$x) is wrongly introduced.
In terms of the string as an output of the serialization: instead of an 'r:' an 'R:' is used.

Run the test script twice: first without the marked two lines (see code) and second with these two lines. 

What is expected:
In the sample code the $Obj1 shows the expected result. $Obj2 should also show this result.

What the actual result is:
With the two marked lines uncommented in code, $Obj2 shows a wrong result.
 
DESCRIPTION:
Without the two lines in the contructor all is correct. The produced string ($txt1) by serialization is:
    O:2:"C1":2:{s:4:"arr1";a:1:{i:0;r:1;}s:4:"arr2";a:1:{i:0;r:1;}}
Unserialization of this string creates an object ($Obj2) which is identical with the original object ($Obj1). This object "behaves" quite correct: after assigning the value '50' to its member arr2[0] the content of its member arr1[0] remains unchanged, i.e. it still holds a reference to the object itself ($Obj2). That's correct because in the constructor there is an assigning "by value", i.e. $this->arr2[0] does NOT refer to the array element $this->arr1[0].

With the two lines in the constructor the result is wrong. The produced string ($txt1) by serialization is:
    O:2:"C1":2:{s:4:"arr1";a:1:{i:0;R:1;}s:4:"arr2";a:1:{i:0;r:1;}}
Notice: the occurence of the first 'r:' in the middle of the string changed to 'R:' (from lower case to upper case letter!).
The two lines simply introduce a reference of a local variable to arr1[0] and remove (unset) it immediately after. Therefore the resulting object should be exactly the same as without these two lines. But the output string of the serialization now shows a "real" reference from arr2[0] to arr1[0]! The concequence of this bug is, that after unserialization (creation of an object from the serialized string) there is a "connection" (a real reference) from the member arr2[0] to the member arr1[0], which was not the case in the original object! Now changing the content of arr2[0] also (wrongly) changes the content of arr1[0].

It seems that this bug only occures when a recursion exists. The line '$this->arr1[0] = $this;' in the constructor introduces this recursion. This was done here in this simple way only for demonstration purpose.
The bug also occures when the recursion exists much more complicate/indirect (i.e. via a chain of many other objects) and also if it's done in any other method of the objects than the constructor. 
Because recursion is needed for this bug, as a concequence the reported bug only occures when an object is assigned to the member variable. The bug does not occure when simple values are assigned (because values can't form a recursion).

I consider this bug as very serious! Because PHP uses serialization for saving (session-)variables between script calls all objects containing a recursion will be wrong after repetitive script calls!


Test script:
---------------
<?php
class C1
{
    public $arr1 = array();
    public $arr2 = array();
    public function __construct()
    {
        $this->arr1[0] = $this;
        $this->arr2[0] = $this->arr1[0];
        // ***** Run the test without and with the following two lines:
        $var1 = &$this->arr1[0];  // Set a reference...
        unset($var1);             // ... and unset it. 
    }
}
echo '<pre>';
$Obj1 = new C1();
$txt1 = serialize($Obj1);
$Obj2 = unserialize($txt1);
$Obj1->arr2[0] = 50;
print_r($Obj1);
$Obj2->arr2[0] = 50;
print_r($Obj2);
echo '</pre>';
?>

Expected result:
----------------
C1 Object
(
    [arr1] => Array
        (
            [0] => C1 Object
 *RECURSION*
        )

    [arr2] => Array
        (
            [0] => 50
        )

)
C1 Object
(
    [arr1] => Array
        (
            [0] => C1 Object
 *RECURSION*
        )

    [arr2] => Array
        (
            [0] => 50
        )

)

Actual result:
--------------
C1 Object
(
    [arr1] => Array
        (
            [0] => C1 Object
 *RECURSION*
        )

    [arr2] => Array
        (
            [0] => 50
        )

)
C1 Object
(
    [arr1] => Array
        (
            [0] => 50
        )

    [arr2] => Array
        (
            [0] => 50
        )

)

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-05-17 09:40 UTC] laruence@php.net
Automatic comment on behalf of laruence@gmail.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=7989db975f325d83b461a46c3dc75a81fcc27795
Log: Fixed bug #72229 (Wrong reference when serialize/unserialize an object)
 [2016-05-17 09:40 UTC] laruence@php.net
-Status: Open +Status: Closed
 [2016-05-17 09:41 UTC] laruence@php.net
Automatic comment on behalf of laruence@gmail.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=7989db975f325d83b461a46c3dc75a81fcc27795
Log: Fixed bug #72229 (Wrong reference when serialize/unserialize an object)
 [2016-07-20 11:31 UTC] davey@php.net
Automatic comment on behalf of laruence@gmail.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=7989db975f325d83b461a46c3dc75a81fcc27795
Log: Fixed bug #72229 (Wrong reference when serialize/unserialize an object)
 
PHP Copyright © 2001-2025 The PHP Group
All rights reserved.
Last updated: Mon Mar 31 07:01:29 2025 UTC