View Issue Details

IDProjectCategoryView StatusLast Update
0001822XdebugUncategorizedpublic2020-07-27 21:44
ReporterfpoirotteAssigned Toderick 
PrioritylowSeveritytweakReproducibilityalways
Status resolvedResolutionno change required 
Product Version2.9.6 
Target VersionFixed in Version 
Summary0001822: XDebug changes the output of serialize() for classes that use __sleep() with binary data
DescriptionHello,

I'm not sure if this is an issue with XDebug or in the PHP interpreter itself, but when calling serialize() on an object whose class uses the __sleep() magic method to provide serialization, the output changes depending on whether XDebug is loaded or not.
(using the \Serializable interface instead of __sleep() does not trigger the issue since the serialization logic is different in that case)

When XDebug is not loaded, the test script returns:
string(50) "O:7:"Sleeper":1:{s:13:"Sleeperdata";s:4:"test";}"
string(47) "O:7:"Sleeper":1:{s:13:"Sleeperdata";s:1:"é";}"

When XDebug is enabled, the following is returned instead:
/tmp/test.php:18:
string(50) "O:7:"Sleeper":1:{s:13:"\000Sleeper\000data";s:4:"test";}"
/tmp/test.php:19:
string(47) "O:7:"Sleeper":1:{s:13:"\000Sleeper\000data";s:1:"é";}"

I'd expect the result of serialize() to be the same whether XDebug is enabled or not.
I think PHP may also be at fault here because the length for the "s" type in the serialized output seems to be incorrect ("Sleeperdata" is only 11 bytes long).

Best regards,
François
Steps To Reproduce<?php

class Sleeper
{
    private $data;

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

    public function __sleep()
    {
        return ['data'];
    }
}

var_dump(serialize(new Sleeper("test")));
var_dump(serialize(new Sleeper("\xC3\xA9")));
Additional Information$ /usr/bin/php -v
PHP 7.4.5 (cli) (built: Jun 3 2020 20:55:00) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
    with Zend OPcache v7.4.5, Copyright (c), by Zend Technologies
    with Xdebug v2.9.6, Copyright (c) 2002-2020, by Derick Rethans

$ /usr/bin/php -m
[PHP Modules]
calendar
Core
ctype
date
dom
exif
FFI
fileinfo
filter
ftp
gd
gettext
gmp
hash
iconv
intl
json
libxml
openssl
pcntl
pcre
PDO
Phar
posix
readline
Reflection
session
shmop
SimpleXML
sockets
sodium
SPL
standard
sysvmsg
sysvsem
sysvshm
tokenizer
xdebug
xml
xmlreader
xmlwriter
xsl
Zend OPcache
zlib

[Zend Modules]
Xdebug
Zend OPcache
TagsNo tags attached.
Operating SystemDebian GNU/Linux testing (11 / Bullseye)
PHP Version7.4.0-7.4.4

Activities

derick

2020-07-27 13:40

administrator   ~0005431

Hi!

Xdebug does not change the output of serialise. I've modified your script a little:

<?php
class Sleeper
{
    private $data;

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

    public function __sleep()
    {
        return ['data'];
    }
}

echo serialize(new Sleeper("test")), "\n";
echo serialize(new Sleeper("\xC3\xA9")), "\n";


With Xdebug:
derick@singlemalt:~$ php /tmp/1822.php && php /tmp/1822.php | md5sum
O:7:"Sleeper":1:{s:13:"Sleeperdata";s:4:"test";}
O:7:"Sleeper":1:{s:13:"Sleeperdata";s:2:"é";}
f3015d04860932275a7e627d3ef5b4f2  -


Without Xdebug:
derick@singlemalt:~$ php -n /tmp/1822.php && php -n /tmp/1822.php | md5sum
O:7:"Sleeper":1:{s:13:"Sleeperdata";s:4:"test";}
O:7:"Sleeper":1:{s:13:"Sleeperdata";s:2:"é";}
f3015d04860932275a7e627d3ef5b4f2  -


The difference is purely in the output of xdebug's var_dump, where it escapes the \0 characters that are present in the original serialize() output:

derick@singlemalt:~$ php -n /tmp/1822.php | od -t x1
0000000 4f 3a 37 3a 22 53 6c 65 65 70 65 72 22 3a 31 3a
0000020 7b 73 3a 31 33 3a 22 00 53 6c 65 65 70 65 72 00
0000040 64 61 74 61 22 3b 73 3a 34 3a 22 74 65 73 74 22
0000060 3b 7d 0a 4f 3a 37 3a 22 53 6c 65 65 70 65 72 22
0000100 3a 31 3a 7b 73 3a 31 33 3a 22 00 53 6c 65 65 70
0000120 65 72 00 64 61 74 61 22 3b 73 3a 32 3a 22 c3 a9
0000140 22 3b 7d 0a

(Spot the "00" in there)

IMO, Xdebug does the right thing and instead outputs the \0 characters as "\000".

fpoirotte

2020-07-27 21:44

reporter   ~0005432

I see. Thanks for clarifying what's happening here!

Issue History

Date Modified Username Field Change
2020-07-26 18:32 fpoirotte New Issue
2020-07-27 13:40 derick Assigned To => derick
2020-07-27 13:40 derick Status new => resolved
2020-07-27 13:40 derick Resolution open => no change required
2020-07-27 13:40 derick Note Added: 0005431
2020-07-27 21:44 fpoirotte Note Added: 0005432