php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #73253 Incorrect references when inheriting the Serialization interface class
Submitted: 2016-10-05 22:34 UTC Modified: 2017-01-01 12:27 UTC
Votes:1
Avg. Score:3.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:1 (100.0%)
From: illibejiep at gmail dot com Assigned:
Status: Duplicate Package: Scripting Engine problem
PHP Version: Irrelevant OS: Linux
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: illibejiep at gmail dot com
New email:
PHP Version: OS:

 

 [2016-10-05 22:34 UTC] illibejiep at gmail dot com
Description:
------------
The Serialization interface method 'unserialize' incorrectly resolves serialized string references when called from children classes.

Test script:
---------------
<?php

class C {
    private $c;

    public function setC($c)
    {
        $this->c = $c;
    }

    public function getC()
    {
        return $this->c;
    }
}

class A implements Serializable
{
    private $c;

    function __construct($c)
    {
        $this->c = $c;
    }

    public function serialize()
    {
        return serialize($this->c);
    }

    public function unserialize($serialized)
    {
        $this->c = unserialize($serialized);
        echo "inner child serialized:\n$serialized\n\n";
        echo "inner child unserialized:\n";
        var_dump($this->c);
    }
}

class B extends A implements Serializable
{
    private $str = 'asdf';

    public function serialize()
    {
        $a = [$this->str, parent::serialize()];

        return serialize($a);
    }

    public function unserialize($serialized)
    {
        echo "inner parent serialized:\n$serialized\n\n";
        $a = unserialize($serialized);
        echo "inner parent unserialized\n";
        var_dump($a);

        $this->str = $a[0];
        parent::unserialize($a[1]);
    }
}

$c = new C();
$c->setC($c);

$a = new A($c);

echo "Parent class:\n";
var_dump($a);
$s = serialize($a);
var_dump($s);
echo "Unserializing parent class:\n";
$unsA = unserialize($s);
echo "Unserialized parent class:\n";
var_dump($unsA);

$b = new B($c);

echo "\nChild class:\n";
var_dump($b);
$s = serialize($b);
var_dump($s);
echo "Unserializing child class:\n";
$unsB = unserialize($s);
echo "Unserialized child class:\n";
var_dump($unsB);


Expected result:
----------------
The unserialized child class should have the same structure.

Actual result:
--------------
Parent class:
object(A)#2 (1) {
  ["c":"A":private]=>
  object(C)#1 (1) {
    ["c":"C":private]=>
    *RECURSION*
  }
}
string(40) "C:1:"A":27:{O:1:"C":1:{s:4:"Cc";r:2;}}"
Unserializing parent class:
inner child serialized:
O:1:"C":1:{s:4:"Cc";r:2;}

inner child unserialized:
object(C)#4 (1) {
  ["c":"C":private]=>
  *RECURSION*
}
Unserialized parent class:
object(A)#3 (1) {
  ["c":"A":private]=>
  object(C)#4 (1) {
    ["c":"C":private]=>
    *RECURSION*
  }
}

Child class:
object(B)#5 (2) {
  ["str":"B":private]=>
  string(4) "asdf"
  ["c":"A":private]=>
  object(C)#1 (1) {
    ["c":"C":private]=>
    *RECURSION*
  }
}
string(73) "C:1:"B":60:{a:2:{i:0;s:4:"asdf";i:1;s:27:"O:1:"C":1:{s:4:"Cc";r:2;}";}}"
Unserializing child class:
inner parent serialized:
a:2:{i:0;s:4:"asdf";i:1;s:27:"O:1:"C":1:{s:4:"Cc";r:2;}";}

inner parent unserialized
array(2) {
  [0]=>
  string(4) "asdf"
  [1]=>
  string(27) "O:1:"C":1:{s:4:"Cc";r:2;}"
}
inner child serialized:
O:1:"C":1:{s:4:"Cc";r:2;}

inner child unserialized:
object(C)#7 (1) {
  ["c":"C":private]=>
  array(2) {
    [0]=>
    string(4) "asdf"
    [1]=>
    string(27) "O:1:"C":1:{s:4:"Cc";r:2;}"
  }
}
Unserialized child class:
object(B)#6 (2) {
  ["str":"B":private]=>
  string(4) "asdf"
  ["c":"A":private]=>
  object(C)#7 (1) {
    ["c":"C":private]=>
    array(2) {
      [0]=>
      string(4) "asdf"
      [1]=>
      string(27) "O:1:"C":1:{s:4:"Cc";r:2;}"
    }
  }
}

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2017-01-01 12:27 UTC] nikic@php.net
-Status: Open +Status: Duplicate
 [2017-01-01 12:27 UTC] nikic@php.net
The problem here is that in unserialize() you're performing unserializations in a different order than you performing the serializations in serialize(). This is illegal, because references (and object references) in the serialization format are order-dependent.

I'm marking this as a duplicate of bug #66052, which is another complaint about this behavior, if from a slightly different angle.
 
PHP Copyright © 2001-2025 The PHP Group
All rights reserved.
Last updated: Sun Feb 16 16:01:29 2025 UTC