php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #33586 Serialization breaks references
Submitted: 2005-07-06 12:03 UTC Modified: 2006-03-14 16:44 UTC
Votes:69
Avg. Score:1.9 ± 1.4
Reproduced:8 of 20 (40.0%)
Same Version:62 (775.0%)
Same OS:63 (787.5%)
From: wmeler at wp dot pl Assigned: dmitry (profile)
Status: Not a bug Package: Scripting Engine problem
PHP Version: 5CVS-2005-07-06 OS: *
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: wmeler at wp dot pl
New email:
PHP Version: OS:

 

 [2005-07-06 12:03 UTC] wmeler at wp dot pl
Description:
------------
After serializing variable with circular reference you get 2 copies of root variable.
Look at output of reproduce code - var_dump outputs should be the same but they are not.

for code: 

$c['d2']=&$d;
$d['c2']=&$c;
echo serialize($c);

you get

a:1:{s:2:"d2";a:1:{s:2:"c2";a:1:{s:2:"d2";R:2;}}}

I think that it should be something like

a:1:{s:2:"d2";a:1:{s:2:"c2";R:1;}}


Reproduce code:
---------------
<?
$c['d2']=&$d;
$d['c2']=&$c;
$x=unserialize(serialize($c));
$x['x']='x';
$c['x']='x';
var_dump($c);
var_dump($x);


Expected result:
----------------
array(2) {
  ["d2"]=>
  &array(1) {
    ["c2"]=>
    &array(2) {
      ["d2"]=>
      &array(1) {
        ["c2"]=>
        &array(2) {
          ["d2"]=>
          *RECURSION*
          ["x"]=>
          string(1) "x"
        }
      }
      ["x"]=>
      string(1) "x"
    }
  }
  ["x"]=>
  string(1) "x"
}
array(2) {
  ["d2"]=>
  &array(1) {
    ["c2"]=>
    &array(2) {
      ["d2"]=>
      &array(1) {
        ["c2"]=>
        &array(2) {
          ["d2"]=>
          *RECURSION*
          ["x"]=>
          string(1) "x"
        }
      }
      ["x"]=>
      string(1) "x"
    }
  }
  ["x"]=>
  string(1) "x"
}


Actual result:
--------------
array(2) {
  ["d2"]=>
  &array(1) {
    ["c2"]=>
    &array(2) {
      ["d2"]=>
      &array(1) {
        ["c2"]=>
        &array(2) {
          ["d2"]=>
          *RECURSION*
          ["x"]=>
          string(1) "x"
        }
      }
      ["x"]=>
      string(1) "x"
    }
  }
  ["x"]=>
  string(1) "x"
}
array(2) {
  ["d2"]=>
  &array(1) {
    ["c2"]=>
    array(1) {
      ["d2"]=>
      &array(1) {
        ["c2"]=>
        array(1) {
          ["d2"]=>
          *RECURSION*
        }
      }
    }
  }
  ["x"]=>
  string(1) "x"
}


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2005-07-06 12:17 UTC] tony2001@php.net
Please try using this CVS snapshot:

  http://snaps.php.net/php5-latest.tar.gz
 
For Windows:
 
  http://snaps.php.net/win32/php5-win32-latest.zip


 [2005-07-06 12:51 UTC] wmeler at wp dot pl
I've tried - nothing changed
 [2005-07-22 01:03 UTC] sniper@php.net
In your example you're making a reference to a non-existing variable. Please come up with something more realistic.

 [2005-07-22 08:52 UTC] wmeler at wp dot pl
Do you want simplest to debug example or complicated real world example?

How about this :

<?
$c = array();
$d = array();

$c['d2']=&$d;
$d['c2']=&$c;
$x=unserialize(serialize($c));
$x['x']='x';
$c['x']='x';
var_dump($c);
var_dump($x);
?>

outputs remain the same

you can even substitute 'c' with 'parent' and 'd' with 'child' which makes it more real but this would change outputs
 [2005-09-02 18:28 UTC] sr at brightlight dot ch
I experienced a similar problem. An even simpler setup 
already breaks unserialisation (php 5.0.4):

    $rec        = array('rec' => 'x');
    $rec['rec']    = &$rec;
    echo "print_r:\n".print_r($rec, true);
    echo "\nafter unserialisation:\n".print_r(unserialize
(serialize($rec)), true);

The output will be:
print_r:
Array
(
    [rec] => Array
 *RECURSION*
)

after unserialisation:
Array
(
    [rec] => Array
        (
            [rec] => 
        )

)

With a few more dimensions before the recursion php will 
even crash on OS X 10.4.1

regards
 [2005-10-07 04:36 UTC] james at gogo dot co dot nz
This has always been a problem, at least in 4.x (I presume it still is the same), I wrote an article about it a couple of years back now.

http://code.gogo.co.nz/dev-2-dev/serialize-unserialize.html

The workaround that worked at the time at least is to force passing in a reference:
  $serializedFoo = serialize(&$myFoo);
 [2005-11-07 02:27 UTC] jfranklin at gmail dot com
I apologize for "cluttering the database" as you say, but this would be a super bug to put some time into and get fixed.
 [2006-03-14 16:44 UTC] dmitry@php.net
serialize() accepts argument by value and unserialize() returns by value so these function cannot be used directly to serialize/deserialize references.

However it is possible do it using additional top-level container. The following exaple produces output that you are expecting.

<?php
function serialize_ref(&$c) {
	return serialize(array(&$c));
}
function &unserialize_ref($s) {
	$ar = unserialize($s);
	return $ar[0];
}

$c=array();
$d=array();
$c['d2']=&$d;
$d['c2']=&$c;
$x=&unserialize_ref(serialize_ref($c));
$x['x']='x';
$c['x']='x';
var_dump($c);
var_dump($x);
/* remove circular dependencies to avoid memory leaks */
$c['d2'] = null;
$x['d2'] = null;
?>


 
PHP Copyright © 2001-2025 The PHP Group
All rights reserved.
Last updated: Wed Jul 02 01:01:34 2025 UTC