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 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: 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

Add a Patch

Pull Requests

Add a Pull Request

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-2020 The PHP Group
All rights reserved.
Last updated: Mon Sep 21 10:01:23 2020 UTC