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 this is not your bug, you can add a comment by following this link.
If this is your bug, but 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

Add a Patch

Pull Requests

Add a Pull Request

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-2024 The PHP Group
All rights reserved.
Last updated: Fri Mar 29 11:01:29 2024 UTC