php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #65967 SplObjectStorage contains corrupt member variables after garbage collection
Submitted: 2013-10-25 16:25 UTC Modified: 2016-03-18 19:39 UTC
Votes:15
Avg. Score:4.2 ± 0.8
Reproduced:14 of 14 (100.0%)
Same Version:9 (64.3%)
Same OS:10 (71.4%)
From: crog at gustavus dot edu Assigned: nikic (profile)
Status: Closed Package: SPL related
PHP Version: 5.2+ OS: Any
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: crog at gustavus dot edu
New email:
PHP Version: OS:

 

 [2013-10-25 16:25 UTC] crog at gustavus dot edu
Description:
------------
If garbage collection is run after creating an SplObjectStorage instance, the object will contain a property which cannot be processed by several other PHP functions (namely, serialization and variable exporting [var_dump, var_export, etc]).

This is caused by the "\x00gcdata" property that is created in the spl_object_storage_get_gc function in spl_observer.c:365 (in php 5.4). This property gets included in the object's property collection and prevents the object from being used by anything that scans the property collection.

Test script:
---------------
$objstore = new SplObjectStorage();
gc_collect_cycles();

var_dump($objstore);

print serialize($objstore);

Expected result:
----------------
object(SplObjectStorage)[6]
C:16:"SplObjectStorage":14:{x:i:0;m:a:0:{}}

Actual result:
--------------
( ! ) Notice: Corrupt member variable name in /cis/www/rog/tester.php on line 97
Call Stack
#	Time	Memory	Function	Location
1	0.0005	308976	{main}( )	../tester.php:0
2	0.0027	768160	var_dump ( ... )	../tester.php:97
Dump $_POST

object(SplObjectStorage)[6]
  public '' => 
    array (size=0)
      empty
C:16:"SplObjectStorage":34:{x:i:0;m:a:1:{s:7:"gcdata";a:0:{}}

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2013-10-29 14:25 UTC] crog at gustavus dot edu
We've discovered that this problem is related to a segfault/zend_mm_heap corruption that occurs when unserializing a large (?) object consisting of several SplObjectStorage instances.

We've temporarily worked around the issue with a simple string replacement on serialization:

$serialized = str_replace("\x00gcdata", '_gcdata', serialize($this->data));

Of course, this leaves the gcdata floating around with no real purpose and we're not sure of the long-term effects of the eventual doubling of that _gcdata variable, so we're hoping for a fix sooner than later.


Backtrace:
(Note: This was taken with the garbage collection disabled. When GC is enabled, the heap is simply corrupted [zend_mm_heap corrupted] and doesn't fail with a core dump/backtrace)

(gdb) bt full
#0  zend_mm_remove_from_free_list (heap=0xbe42e0, mm_block=0x1379478)
    at /usr/src/debug/php-5.4.21/Zend/zend_alloc.c:833
        prev = 0x68cc2cb934f70384
        next = 0x29
#1  0x00000000005bcdd3 in _zend_mm_free_int (heap=0xbe42e0, p=0x1379488)
    at /usr/src/debug/php-5.4.21/Zend/zend_alloc.c:2101
        mm_block = 0x1379478
        next_block = 0x1379478
        size = 0
#2  0x00000000005ef4d1 in zend_hash_destroy (ht=0x12f2250)
    at /usr/src/debug/php-5.4.21/Zend/zend_hash.c:565
        p = 0x1379510
        q = 0x1379488
#3  0x000000000060417c in zend_object_std_dtor (object=0x1312780)
    at /usr/src/debug/php-5.4.21/Zend/zend_objects.c:44
No locals.
#4  0x0000000000604209 in zend_objects_free_object_storage (object=0x1312780)
    at /usr/src/debug/php-5.4.21/Zend/zend_objects.c:137
No locals.
#5  0x000000000060a14c in zend_objects_store_del_ref_by_handle_ex (handle=416,
    handlers=<value optimized out>) at /usr/src/debug/php-5.4.21/Zend/zend_objects_API.c:226
        __orig_bailout = 0x7fffffffc780
        __bailout = {{__jmpbuf = {19999776, 3201897196840651886, 20502008, 140737488349162,
              0, 0, -3201899731257029522, 3201898902524759150}, __mask_was_saved = 0,
            __saved_mask = {__val = {140732768597912, 1376, 6016370, 88, 6016370, 136,
                6016370, 104, 6016370, 20503224, 19865104, 176, 6016370, 272, 6016370,
                1200}}}}
        obj = 0x7ffee6694838
        failure = <value optimized out>
#6  0x000000000060a173 in zend_objects_store_del_ref (zobject=0x1312c20)
    at /usr/src/debug/php-5.4.21/Zend/zend_objects_API.c:178
        handle = <value optimized out>
#7  0x00000000005d478a in _zval_dtor (zval_ptr=0x138d5a8)
    at /usr/src/debug/php-5.4.21/Zend/zend_variables.h:35
No locals.
#8  _zval_ptr_dtor (zval_ptr=0x138d5a8)
    at /usr/src/debug/php-5.4.21/Zend/zend_execute_API.c:436
No locals.
#9  0x00000000005ef4ab in zend_hash_destroy (ht=0x12f3130)
    at /usr/src/debug/php-5.4.21/Zend/zend_hash.c:560
        p = 0x138d5f8
        q = 0x138d590
#10 0x000000000060417c in zend_object_std_dtor (object=0x1313f38)
    at /usr/src/debug/php-5.4.21/Zend/zend_objects.c:44
No locals.
#11 0x0000000000604209 in zend_objects_free_object_storage (object=0x1313f38)
    at /usr/src/debug/php-5.4.21/Zend/zend_objects.c:137
No locals.
#12 0x000000000060a14c in zend_objects_store_del_ref_by_handle_ex (handle=423,
    handlers=<value optimized out>) at /usr/src/debug/php-5.4.21/Zend/zend_objects_API.c:226
        __orig_bailout = 0x7fffffffc900
        __bailout = {{__jmpbuf = {140732764080624, 3201897323198254190, 20509584,
              140737488349162, 0, 0, -3201899731158463378, 3201898902524759150},
            __mask_was_saved = 0, __saved_mask = {__val = {3201897415757106286, 0,
                140737488349162, 0, 0, 88, 6016370, 19858328, 19854112, 80, 6016370, 136,
                6016370, 96, 6016370, 20509848}}}}
        obj = 0x7ffee66949f8
        failure = <value optimized out>
#13 0x000000000060a173 in zend_objects_store_del_ref (zobject=0x1314f70)
    at /usr/src/debug/php-5.4.21/Zend/zend_objects_API.c:178
        handle = <value optimized out>
#14 0x00000000005d478a in _zval_dtor (zval_ptr=0x1379f20)
    at /usr/src/debug/php-5.4.21/Zend/zend_variables.h:35
No locals.
#15 _zval_ptr_dtor (zval_ptr=0x1379f20)
    at /usr/src/debug/php-5.4.21/Zend/zend_execute_API.c:436
No locals.
#16 0x0000000000505d89 in spl_object_storage_dtor (element=0x1379f20)
    at /usr/src/debug/php-5.4.21/ext/spl/spl_observer.c:182
No locals.
#17 0x00000000005ef4ab in zend_hash_destroy (ht=0x138c7f0)
    at /usr/src/debug/php-5.4.21/Zend/zend_hash.c:560
        p = 0x138f390
        q = 0x138e180
#18 0x0000000000507512 in spl_SplOjectStorage_free_storage (object=0x138c7d0)
    at /usr/src/debug/php-5.4.21/ext/spl/spl_observer.c:103
        intern = 0x138c7d0
#19 0x000000000060a14c in zend_objects_store_del_ref_by_handle_ex (handle=422,
    handlers=<value optimized out>) at /usr/src/debug/php-5.4.21/Zend/zend_objects_API.c:226
        __orig_bailout = 0x7fffffffca90
        __bailout = {{__jmpbuf = {19918568, 3201897197490769006, 20420720, 140737488349162,
              0, 0, -3201899731074577298, 3201898902524759150}, __mask_was_saved = 0,
            __saved_mask = {__val = {140737488341712, 140732764073968, 3201897277952199790,
                20436200, 140737488349162, 32, 6016370, 240, 6016370, 20421464, 19874576, 80,
                6016370, 408, 6016370, 936}}}}
        obj = 0x7ffee66949b8
        failure = <value optimized out>
#20 0x000000000060a173 in zend_objects_store_del_ref (zobject=0x12feee8)
    at /usr/src/debug/php-5.4.21/Zend/zend_objects_API.c:178
        handle = <value optimized out>
#21 0x00000000005d478a in _zval_dtor (zval_ptr=0x1379820)
    at /usr/src/debug/php-5.4.21/Zend/zend_variables.h:35
No locals.
#22 _zval_ptr_dtor (zval_ptr=0x1379820)
    at /usr/src/debug/php-5.4.21/Zend/zend_execute_API.c:436
No locals.
#23 0x00000000005ef4ab in zend_hash_destroy (ht=0x12f2250)
    at /usr/src/debug/php-5.4.21/Zend/zend_hash.c:560
        p = 0x1379870
        q = 0x1379808
#24 0x000000000060417c in zend_object_std_dtor (object=0x1312780)
    at /usr/src/debug/php-5.4.21/Zend/zend_objects.c:44
No locals.
#25 0x0000000000604209 in zend_objects_free_object_storage (object=0x1312780)
    at /usr/src/debug/php-5.4.21/Zend/zend_objects.c:137
No locals.
#26 0x000000000060a14c in zend_objects_store_del_ref_by_handle_ex (handle=416,
    handlers=<value optimized out>) at /usr/src/debug/php-5.4.21/Zend/zend_objects_API.c:226
        __orig_bailout = 0x7fffffffcc50
        __bailout = {{__jmpbuf = {140732764080176, 3201897196626742382, 0, 140737488349162,
              0, 0, -3201899730992788370, 3201898902524759150}, __mask_was_saved = 0,
            __saved_mask = {__val = {3201897420299537518, 19981896, 140737488349162, 0, 0,
                15244844342691597422, 3201898902524759150, 0, 0, 15244844342687403118,
                3201898902524759150, 0, 6016370, 64, 6016370, 88}}}}
        obj = 0x7ffee6694838
        failure = <value optimized out>
#27 0x000000000060a173 in zend_objects_store_del_ref (zobject=0x1312c20)
    at /usr/src/debug/php-5.4.21/Zend/zend_objects_API.c:178
        handle = <value optimized out>
#28 0x00000000005d478a in _zval_dtor (zval_ptr=0x12efa20)
    at /usr/src/debug/php-5.4.21/Zend/zend_variables.h:35
No locals.
#29 _zval_ptr_dtor (zval_ptr=0x12efa20)
    at /usr/src/debug/php-5.4.21/Zend/zend_execute_API.c:436
No locals.
#30 0x00000000005ef4ab in zend_hash_destroy (ht=0x12f0b90)
    at /usr/src/debug/php-5.4.21/Zend/zend_hash.c:560
        p = 0x0
        q = 0x12efa08
#31 0x00000000005e148b in _zval_dtor_func (zvalue=0x135b070)
    at /usr/src/debug/php-5.4.21/Zend/zend_variables.c:45
No locals.
#32 0x00000000005d478a in _zval_dtor (zval_ptr=0x130e660)
    at /usr/src/debug/php-5.4.21/Zend/zend_variables.h:35
No locals.
#33 _zval_ptr_dtor (zval_ptr=0x130e660)
    at /usr/src/debug/php-5.4.21/Zend/zend_execute_API.c:436
No locals.
#34 0x00000000005ef4ab in zend_hash_destroy (ht=0x13535a8)
    at /usr/src/debug/php-5.4.21/Zend/zend_hash.c:560
        p = 0x130eb30
        q = 0x130e648
#35 0x000000000060417c in zend_object_std_dtor (object=0x1353ce8)
    at /usr/src/debug/php-5.4.21/Zend/zend_objects.c:44
No locals.
#36 0x0000000000604209 in zend_objects_free_object_storage (object=0x1353ce8)
    at /usr/src/debug/php-5.4.21/Zend/zend_objects.c:137
No locals.
#37 0x0000000000609c4c in zend_objects_store_free_object_storage (objects=0x9f3740)
    at /usr/src/debug/php-5.4.21/Zend/zend_objects_API.c:97
        obj = <value optimized out>
        i = <value optimized out>
#38 0x00000000005d5953 in shutdown_executor ()
    at /usr/src/debug/php-5.4.21/Zend/zend_execute_API.c:295
        __orig_bailout = 0x7fffffffe360
        __bailout = {{__jmpbuf = {10433408, 3201899266092141678, 140737488348528,
              140737488349162, 0, 0, -3201899730923582354, 3201899276952112238},
            __mask_was_saved = 0, __saved_mask = {__val = {3201899133432204398, 0, 6016370,
                32, 6016370, 184, 6016370, 140737353949184, 15537104, 104, 6016370,
                140732767562360, 140732767788136, 88, 15432352, 10434720}}}}
#39 0x00000000005e2802 in zend_deactivate () at /usr/src/debug/php-5.4.21/Zend/zend.c:938
No locals.
#40 0x0000000000584f7c in php_request_shutdown (dummy=<value optimized out>)
    at /usr/src/debug/php-5.4.21/main/main.c:1808
        report_memleaks = 1 '\001'
#41 0x000000000068c55f in do_cli (argc=4, argv=0x7fffffffe558)
    at /usr/src/debug/php-5.4.21/sapi/cli/php_cli.c:1172
        c = <value optimized out>
        file_handle = {type = ZEND_HANDLE_MAPPED,
          filename = 0x7fffffffe7ea "/usr/bin/phpunit", opened_path = 0x0, handle = {
            fd = -134399096, fp = 0x7ffff7fd3b88, stream = {handle = 0x7ffff7fd3b88,
              isatty = 0, mmap = {len = 2019, pos = 0, map = 0x7ffee6f94000,
                buf = 0x7ffee6f9400f "", old_handle = 0xeb7c50,
                old_closer = 0x5f8a70 <zend_stream_stdio_closer>},
              reader = 0x5f9090 <zend_stream_stdio_reader>,
              fsizer = 0x5f8b20 <zend_stream_stdio_fsizer>,
              closer = 0x5f9010 <zend_stream_mmap_closer>}}, free_filename = 0 '\000'}
        behavior = <value optimized out>
        reflection_what = <value optimized out>
        request_started = 1
        exit_status = 0
        php_optarg = 0x7fffffffe7de "gc_enable=0"
        php_optind = 4
        exec_direct = <value optimized out>
        exec_run = <value optimized out>
        exec_begin = <value optimized out>
        exec_end = <value optimized out>
        arg_free = <value optimized out>
        arg_excp = <value optimized out>
        script_file = <value optimized out>
        translated_path = 0xeb7e90 "/usr/bin/phpunit"
        interactive = <value optimized out>
        lineno = 2
        param_error = 0x6f9ff0 "Either execute direct code, process stdin or use a file.\n"
        hide_argv = <value optimized out>
#42 0x000000000068d928 in main (argc=4, argv=0x7fffffffe558)
    at /usr/src/debug/php-5.4.21/sapi/cli/php_cli.c:1365
        __orig_bailout = 0x0
        __bailout = {{__jmpbuf = {7596570286683205949, 4039469594811778698,
              7883960575912274292, 8458716092903159905, 7857145540187679090,
              7306640099802838133, -3201899730208453522, 3201898834450287726},
            __mask_was_saved = 0, __saved_mask = {__val = {140737488348544, 25, 270252091729,
                270278976984, 140737488348144, 270249628040, 270276808342, 194,
                140737488348206, 18446744073600302988, 4096, 0, 0, 0, 6903184, 0}}}}
        c = <value optimized out>
        exit_status = 0
        module_started = 1
        sapi_started = 1
        php_optarg = 0x7fffffffe7de "gc_enable=0"
        php_optind = 3
        use_extended_info = 0
        ini_path_override = 0x0
        ini_entries = 0xbe4250 "html_errors=0\nregister_argc_argv=1\nimplicit_flush=1\noutput_buffering=0\nmax_execution_time=0\nmax_input_time=-1\ngc_enable=0\n"
        ini_entries_len = <value optimized out>
        ini_ignore = 0
        sapi_module = 0x9d8360
 [2013-11-20 14:29 UTC] sjon at hortensius dot net
I am unable to reproduce this in any version, see http://3v4l.org/nRbiO
 [2013-11-22 19:18 UTC] crog at gustavus dot edu
Good catch. When I was writing the script to trigger the issue, I was testing it through the browser. Running on the command-line, I can't trigger it there, either (despite a few efforts at making terribly large circular structures).

Just to be certain, I did run the test again through the browser, ensuring our auto-append and prepends were disabled to check that it still happens (it does).

Some relevant bits from phpinfo():
Build Date      Nov 13 2013 09:29:31 
Server API      Apache 2.0 Handler 
Apache Version  Apache/2.2.15 (Red Hat) 


In any event, it doesn't even matter. The problem is that SplObjectStorage adds properties that contain null bytes (which you can see by looking at the source -- it's even commented as intentional to "make tampering in user-land more difficult" (spl_observer.c:391).

The negative effects of this "bug," aren't that the property exists, it's that other PHP functions explode horribly when they encounter a property containing a null byte. If that's all we're interested in observing, we can do so a lot easier (and on the command-line :D ) with the following:

  var_dump((object) ["\x00key" => "value"]);


So, that said, I suppose this issue could be resolved by changing everything else to not choke on null bytes in property names; but it seems slightly more reasonable to change SplObjectStorage such that it doesn't store its internal data in the object itself (and/or not use a null byte in its property names).
 [2013-11-22 19:25 UTC] crog at gustavus dot edu
Sorry, forgot links:
SplObjectStorage \x00gcdata entry:
http://lxr.php.net/xref/PHP_5_4/ext/spl/spl_observer.c#391

Corrupt member name example:
http://3v4l.org/jfcJr
 [2014-03-02 15:25 UTC] adrian at foeder dot de
Totally having the same issue on Windows 8, PHP 5.4.11 (Zend Server CE).
Did anybody try this with igbinary? Does it happen there too?
 [2014-03-25 13:59 UTC] levim@php.net
-Status: Open +Status: Verified -Operating System: Linux/Redhat +Operating System: Any -PHP Version: 5.4.21 +PHP Version: 5.2+
 [2014-03-25 13:59 UTC] levim@php.net
Can confirm that this affects PHP 5.2 through 5.6 alpha 3 on several OS's.
 [2015-03-13 17:01 UTC] laruence@php.net
Automatic comment on behalf of adam.scarr@99designs.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=950d3d6e9b94b75b266c67bf9e3a85ae9c31905d
Log: Fix bug #69227 and #65967
 [2016-03-18 19:39 UTC] nikic@php.net
-Status: Verified +Status: Closed -Assigned To: +Assigned To: nikic
 [2016-03-18 19:39 UTC] nikic@php.net
Closing, as this is fixed by the aforementioned commit. Automatic closer didn't pick that format up.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Nov 22 17:01:31 2024 UTC