php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #57710 "nested" get calls in __wakeup() functions breaks
Submitted: 2007-06-19 15:19 UTC Modified: 2007-10-17 14:52 UTC
From: uwe at mesecke dot net Assigned: mikael (profile)
Status: Closed Package: memcache (PECL)
PHP Version: 5.2.1 OS: Linux
Private report: No CVE-ID: None
View Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
If you reported this bug, you can edit this bug over here.
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: uwe at mesecke dot net
New email:
PHP Version: OS:

 

 [2007-06-19 15:19 UTC] uwe at mesecke dot net
Description:
------------
When a class instance is get from memcache, it is unserialized before returned. That does not work, when the __wakeup()-function of the class itself asks for another value.

php is from ubuntu feisty (5.2.1-0ubuntu1.2) and php-memcache is compiled with a small patch to fix the different php include paths on ubuntu.

Reproduce code:
---------------
function errorCallback($host, $port)
{
        echo "ERROR: $host:$port\n";
}

$mmc = new Memcache;
$mmc->addServer(/* host */ 'localhost', /* port */ 11211, /* persistent */ true, /* weight */ 10, /* timeout */ 10, /* retry time */ 1, /* status */ true, /* error callback */ 'errorCallback');

class A
{
}

class B
{
        protected $a;

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

        public function __sleep()
        {
                $this->c = 'a';
                return array_keys(get_object_vars($this));
        }

        public function __wakeup()
        {
                global $mmc;
                $this->c = $mmc->get('a');
        }
}

$a = new A;
$mmc->set('a', clone $a, 0, 0);

$b = new B;
$mmc->set('b', clone $b, 0, 0);

$c = $mmc->get('b');

var_dump($c);

Expected result:
----------------
The var_dump($c) should print a string representation of an instance of class B...

Actual result:
--------------
the line "$c = $mmc-get('b')" seems to call the error callback function and returns "false" (object not found)

uwe@harry:~$ php mmctest.php
ERROR: localhost:11211
bool(false)

the following is the memcached output with commandline argument -vv:

<32 new client connection
<32 set a 1 0 12
>32 STORED
<32 set b 1 0 41
>32 STORED
<32 get b
>32 sending key b
>32 END
<32 get a
>32 sending key a
>32 END
<32 connection closed.

last thing is the trace log from xdebug:

TRACE START [2007-06-19 19:09:34]
    0.0012      64588   -> {main}() /home/uwe/mmctest.php:0
    0.0014      65072     -> Memcache->addserver(string(9), long, bool, long, long, long, bool, string(13)) /home/uwe/mmctest.php:9
                           >=> TRUE
    0.0017      65592     -> Memcache->set(string(1), class A, long, long) /home/uwe/mmctest.php:38
                           >=> TRUE
    0.0027      66304     -> B->__construct() /home/uwe/mmctest.php:40
                           >=> NULL
    0.0028      66692     -> Memcache->set(string(1), class B, long, long) /home/uwe/mmctest.php:41
    0.0029      66780       -> B->__sleep() /home/uwe/mmctest.php:0
    0.0029      66852         -> get_object_vars(class B) /home/uwe/mmctest.php:27
                               >=> array ('a' => NULL, 'c' => 'a')
    0.0031      67076         -> array_keys(array(2)) /home/uwe/mmctest.php:27
                               >=> array (0 => 'a', 1 => 'c')
                             >=> array (0 => 'a', 1 => 'c')
                           >=> TRUE
    0.0035      67420     -> Memcache->get(string(1)) /home/uwe/mmctest.php:43
    0.0037      75644       -> B->__wakeup() /home/uwe/mmctest.php:0
    0.0037      75644         -> Memcache->get(string(1)) /home/uwe/mmctest.php:33
                               >=> FALSE
                             >=> NULL
    0.0041      67436       -> errorCallback(string(9), long) /home/uwe/mmctest.php:0
                             >=> NULL
                           >=> FALSE
    0.0048      67684     -> var_dump(bool) /home/uwe/mmctest.php:45
                           >=> NULL
                         >=> 1
    0.0054      25208
TRACE END   [2007-06-19 19:09:34]


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2007-06-20 06:13 UTC] uwe at mesecke dot net
I think the problem is, that in mmc_read_value the data is unserialized just after reading it from the line. Now if there is another memcache operation inside the unserializing process, the two requests (and responses) are mixed and the result is a mess. the data should better be read first as a whole and then after the protocol handling is finished the data can be unserialized without interfering other memcache operations.
 [2007-06-20 14:05 UTC] php at koterov dot ru
I have also reproduced this bug.

Seems unserialize() called inside the Memcache::get() must not call Memcache::get() recurrently via __wakeup, or the extension fails.
 [2007-06-21 13:43 UTC] uwe at mesecke dot net
I have written a fix for this issue and uploaded the patch:

http://uwe.ktv-zone.de/extern/php-memcache-nested-gets-fix.patch

The conversion into a zval is no longer done in mmc_read_value() but in a new method called mmc_build_value(). The data that is read from the stream is saved into a linked list that is later converted into zvals when the protocol handling is finished.

I tried to make the change as noninvasive as possible and don't mess with the memory but I must warn you that this was my first experience with php extension programming and the time when I had written C code is also some ages ago.

The Code passed some basic tests, including this bug's reproduction code and some multi-gets. But don't blame me if it burns your house and eats your dog. ;)
 [2007-06-25 04:41 UTC] tony2001 at phpclub dot net
Mikael, could you plz take a look at it?
 [2007-06-26 16:53 UTC] uwe at mesecke dot net
I uploaded a new patch-file that fixes a small bug. I forgot the TSRMLS_CC when invoking mmc_build_value(). Sorry.
 [2007-10-16 08:28 UTC] ohill@php.net
Is there any news on this bug?

I seem to have the same problem with sessions using memcache.
 [2007-10-16 09:14 UTC] uwe at mesecke dot net
In 2.2.0 the bug still exists. I have updated my patch to apply against the current release and uploaded it again:

http://uwe.ktv-zone.de/extern/php-memcache-nested-gets-fix_2.2.0.patch
 [2007-10-17 14:52 UTC] mikael at synd dot info
This bug has been fixed in CVS.

In case this was a documentation problem, the fix will show up at the
end of next Sunday (CET) on pecl.php.net.

In case this was a pecl.php.net website problem, the change will show
up on the website in short time.
 
Thank you for the report, and for helping us make PECL better.


 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Dec 27 03:01:28 2024 UTC