Edit report at https://bugs.php.net/bug.php?id=60701&edit=1

 ID:                 60701
 Comment by:         pada at hrz dot tu-chemnitz dot de
 Reported by:        daan at react dot com
 Summary:            __toString() which stores $this reference triggers
                     segfault (with fix!)
 Status:             Assigned
 Type:               Bug
 Package:            Reproducible crash
 Operating System:   CentOS
 PHP Version:        5.3.8
 Assigned To:        dmitry
 Block user comment: N
 Private report:     N

 New Comment:

This patch does not work for me. I'm still experiencing SegFaults with the 
following code on CentOS 6.0 with php 5.3.3 and 
https://bugs.php.net/patch-display.php?bug_id=60701&patch=bug60701.patch&revision=1327066212
 applied.

Test-Script:

<?php
class C{function f(){$this->o=new O();return$this->o;}function 
__destruct(){}}class O{function __toString(){$this->$this;}}$c=new 
C();$o=$c->f();trim($o);
?>

With the patch applied, I'm still getting SegFaults in 
/var/log/httpd/error_log, but no coredumps any more. This is very strange, 
since coredumping is correctly configured and with other reproducer scripts 
from other bugs I'm getting coredumps.


Previous Comments:
------------------------------------------------------------------------
[2012-02-11 00:49:07] andrew at localcoast dot net

I can produce a similar issue on PHP 5.3.10 on Ubuntu 10.04 LTS x86_64 with the 
patch applied. However, the initial test script provided in the first comment 
runs without trouble.


Here's the backtrace for the issue I am having:

http://paste2.org/p/1900387
#0  0x00007f71fa9b8d11 in gc_zval_possible_root (zv=0x7f7201483740) at 
/home/andrew/.Applications/build/php-5.3.10-patched/Zend/zend_gc.c:143
#1  0x00007f71fa9a777b in zend_hash_destroy (ht=0x7f7201496908) at 
/home/andrew/.Applications/build/php-5.3.10-patched/Zend/zend_hash.c:529
        p = 0x7f7201497c58
#2  0x00007f71fa9ba379 in zend_object_std_dtor (object=0x7f7201497428) at 
/home/andrew/.Applications/build/php-5.3.10-patched/Zend/zend_objects.c:45
#3  0x00007f71fa9ba399 in zend_objects_free_object_storage 
(object=0x7f7201483740) at 
/home/andrew/.Applications/build/php-5.3.10-patched/Zend/zend_objects.c:126
#4  0x00007f71fa9bdba8 in zend_objects_store_free_object_storage 
(objects=0x7f71fb162a18) at 
/home/andrew/.Applications/build/php-5.3.10-patched/Zend/zend_objects_API.c:92
        i = 626
#5  0x00007f71fa98ebfb in shutdown_executor () at 
/home/andrew/.Applications/build/php-5.3.10-patched/Zend/zend_execute_API.c:304
        __bailout = {{__jmpbuf = {140127520564832, -3282099667358606386, 
140127614418320, 0, -4294967295, 140127589456664, -3211606770996110386, 
-3282099660654535730}, __mask_was_saved = 0, __saved_mask = {__val = 
{140127612053568, 96, 140127512287676, 
                140127629890216, 140127638595144, 88, 140127512287676, 592, 
140127512287676, 140127520566336, 140127520563352, 140127520564648, 0, 
18446744069414584321, 140127512403989, 140127520566336}}}}
#6  0x00007f71fa99b612 in zend_deactivate () at 
/home/andrew/.Applications/build/php-5.3.10-patched/Zend/zend.c:891
#7  0x00007f71fa947ad5 in php_request_shutdown (dummy=<value optimized out>) at 
/home/andrew/.Applications/build/php-5.3.10-patched/main/main.c:1661
        report_memleaks = 1 '\001'
#8  0x00007f71faa24a97 in php_apache_request_dtor (r=<value optimized out>) at 
/home/andrew/.Applications/build/php-5.3.10-patched/sapi/apache2handler/sapi_apache2.c:509
#9  php_handler (r=<value optimized out>) at 
/home/andrew/.Applications/build/php-5.3.10-patched/sapi/apache2handler/sapi_apache2.c:681
        ctx = 0x7f7200ae5840
        conf = 0x7f7200689c98
        brigade = 0x7f7200ae6658
        bucket = <value optimized out>
        rv = <value optimized out>
        parent_req = 0x0
#10 0x00007f71ff0e3280 in ap_run_handler (r=0x7f7200ae3d90) at 
/build/buildd/apache2-2.2.14/server/config.c:159
        n = 6
        rv = -2039876096
#11 0x00007f71ff0e6be8 in ap_invoke_handler (r=0x7f7200ae3d90) at 
/build/buildd/apache2-2.2.14/server/config.c:373
        handler = 0x7f7200ad61d8 "Xa\255"
        result = 11362776
        old_handler = 0x7f7200792ec8 "application/x-httpd-php"
        ignore = <value optimized out>
#12 0x00007f71ff0f45fc in ap_internal_redirect (new_uri=<value optimized out>, 
r=<value optimized out>) at 
/build/buildd/apache2-2.2.14/modules/http/http_request.c:501
        new = 0x7f7200ae3d90
        access_status = -2039876096
#13 0x00007f71f664dc95 in ?? () from /usr/lib/apache2/modules/mod_rewrite.so
No symbol table info available.
#14 0x00007f71ff0e3280 in ap_run_handler (r=0x7f7200ad61d8) at 
/build/buildd/apache2-2.2.14/server/config.c:159
        n = 7
        rv = -2039876096
#15 0x00007f71ff0e6be8 in ap_invoke_handler (r=0x7f7200ad61d8) at 
/build/buildd/apache2-2.2.14/server/config.c:373
        handler = 0x0
        result = 0
        old_handler = 0x7f71f6651e58 "redirect-handler"
        ignore = <value optimized out>
#16 0x00007f71ff0f47d8 in ap_process_request (r=0x7f7200ad61d8) at 
/build/buildd/apache2-2.2.14/modules/http/http_request.c:282
        access_status = -2039876096
#17 0x00007f71ff0f1688 in ap_process_http_connection (c=0x7f7200ad0118) at 
/build/buildd/apache2-2.2.14/modules/http/http_core.c:190
        r = 0x7f7200ad61d8
        csd = 0x0
#18 0x00007f71ff0eae38 in ap_run_process_connection (c=0x7f7200ad0118) at 
/build/buildd/apache2-2.2.14/server/connection.c:43
        n = 2
        rv = -2039876096
#19 0x00007f71ff0f97a7 in child_main (child_num_arg=<value optimized out>) at 
/build/buildd/apache2-2.2.14/server/mpm/prefork/prefork.c:662
        current_conn = <value optimized out>
        csd = 0x7f7200acff28
        ptrans = 0x7f7200acfea8
        allocator = 0x7f7200acdda0
        status = <value optimized out>
        i = <value optimized out>
        lr = <value optimized out>
        pollset = 0x7f7200acdfc8
        sbh = 0x7f7200acdfc0
        bucket_alloc = 0x7f7200ad4148
        last_poll_idx = 0
#20 0x00007f71ff0f9a76 in make_child (s=0x7f72005dc938, slot=0) at 
/build/buildd/apache2-2.2.14/server/mpm/prefork/prefork.c:702
#21 0x00007f71ff0fa0c3 in ap_mpm_run (_pconf=<value optimized out>, plog=<value 
optimized out>, s=<value optimized out>) at 
/build/buildd/apache2-2.2.14/server/mpm/prefork/prefork.c:978
        index = <value optimized out>
        remaining_children_to_start = <value optimized out>
        rv = <value optimized out>
#22 0x00007f71ff0cf350 in main (argc=2, argv=0x7fff211385d8) at 
/build/buildd/apache2-2.2.14/server/main.c:742
        c = 88 'X'
        configtestonly = <value optimized out>
        confname = 0x7f71ff0fc08b "/etc/apache2/apache2.conf"
        def_server_root = 0x7f71ff0ffca3 ""
        temp_error_log = 0x0
        error = <value optimized out>
        process = 0x7f72005d4220
        server_conf = 0x7f72005dc938
        pglobal = 0x7f72005d4128
        pconf = 0x7f72005d6138
        plog = 0x7f720060a2d8
        ptemp = 0x7f72005de178
        pcommands = 0x7f72005d8148
        opt = 0x7f72005d8240
        rv = <value optimized out>
        mod = <value optimized out>
        optarg = 0x0

And my PHP compile time options:

./configure --prefix=/opt/php5.3.10 --with-apxs2=/usr/bin/apxs2  
--with-config-file-scan-dir=/etc/php5/apache2/ 
--with-config-file-path=/etc/php5/apache2/ --with-mysql --with-pdo-mysql 
--enable-mbstring --with-mcrypt --with-mysqli --with-gd --with-curl 
--enable-exif --enable-ftp --enable-sockets --with-openssl

Using Xdebug's tracing features, I found that the last series of calls that 
were made were to ->__destruct() on our abstract model class. The code within 
our __destruct() sets instance variable arrays to new arrays, and sets object 
references to null.

When PHP is compiled with debug mode (--enable-debug) enabled, the issue can 
not be reproduced.

------------------------------------------------------------------------
[2012-01-25 09:20:11] daan at react dot com

Working patch fix now included! (tm)

------------------------------------------------------------------------
[2012-01-20 13:28:42] hans at rakers dot org

This bug is caused by zend_std_cast_object_tostring() not checking the refcount 
of readobj when readobj==writeobj. It calls INIT_PZVAL(writeobj) without 
checking the refcount first, causing any further references to this zval to get 
corrupted (in this case, the 'test' property of StringableObject).

My patch against 5.3 is attached.

------------------------------------------------------------------------
[2012-01-10 19:22:39] sjon at hortensius dot net

This bug is not reproducible when php is compiled with enable-debug. It is 
however reproducible in other PHP versions, such as 5.3.7/5.3.6/5.3.5

------------------------------------------------------------------------
[2012-01-10 16:43:17] daan at react dot com

Description:
------------
A simple object construction where a __toString() stores $this, will trigger a 
segfault during garbage collection at the end of the request.

Probably related bug: https://bugs.php.net/bug.php?id=60598
Is a distilled version of this bug: https://bugs.php.net/bug.php?id=60457

Test script:
---------------
<?php
class Container
{
        public function getObject()
        {
                $this->object = new StringableObject();

                return $this->object;
        }

        // This destructor is required to exist to trigger the segfault
        public function __destruct()
        {
        }
}

class StringableObject
{
        public function __toString()
        {
                $this->test = $this;

                return '';
        }
}

$container = new Container();
$object = $container->getObject();

// Any kind of function which triggers a 'to string' object conversion
// Casting $object with (string) will circumvent the problem
echo trim($object);
// Another call is required to corrupt heap
echo trim('test');


Expected result:
----------------
test

Actual result:
--------------
Segfault

gdb backtrace (with commandline PHP with build tag ZEND_DEBUG_OBJECTS)

[Thread debugging using libthread_db enabled]
Allocated object id #1
Allocated object id #2
Increased refcount of object id #2
Decreased refcount of object id #2
testIncreased refcount of object id #1
Decreased refcount of object id #1
Deallocated object id #1

Program received signal SIGSEGV, Segmentation fault.
0x00000000006d4c69 in gc_zval_possible_root (zv=0x1023e40) at /home/sjon/php-
debug/php-5.3.8/Zend/zend_gc.c:143
143            GC_ZOBJ_CHECK_POSSIBLE_ROOT(zv);
(gdb) bt
#0  0x00000000006d4c69 in gc_zval_possible_root (zv=0x1023e40) at 
/home/sjon/php-debug/php-5.3.8/Zend/zend_gc.c:143
#1  0x00000000006c4ad8 in zend_hash_destroy (ht=0x10266d0) at /home/sjon/php-
debug/php-5.3.8/Zend/zend_hash.c:529
#2  0x00000000006d6009 in zend_object_std_dtor (object=0x1023dc8) at 
/home/sjon/php-debug/php-5.3.8/Zend/zend_objects.c:45
#3  0x00000000006d6029 in zend_objects_free_object_storage (object=0x1023dc8) 
at 
/home/sjon/php-debug/php-5.3.8/Zend/zend_objects.c:126
#4  0x00000000006da037 in zend_objects_store_del_ref_by_handle_ex (handle=2, 
handlers=<optimized out>) at /home/sjon/php-debug/php-
5.3.8/Zend/zend_objects_API.c:220
#5  0x00000000006da053 in zend_objects_store_del_ref (zobject=0x1022350) at 
/home/sjon/php-debug/php-5.3.8/Zend/zend_objects_API.c:172
#6  0x00000000006a9571 in _zval_dtor (zvalue=0x1022350) at /home/sjon/php-
debug/php-5.3.8/Zend/zend_variables.h:35
#7  _zval_ptr_dtor (zval_ptr=<optimized out>) at /home/sjon/php-debug/php-
5.3.8/Zend/zend_execute_API.c:447
#8  0x00000000006c3645 in zend_hash_apply_deleter (ht=0xe33188, p=0x1026728) at 
/home/sjon/php-debug/php-5.3.8/Zend/zend_hash.c:612
#9  0x00000000006c4f81 in zend_hash_reverse_apply (ht=0xe33188, 
apply_func=0x6a9430 <zval_call_destructor>) at /home/sjon/php-debug/php-
5.3.8/Zend/zend_hash.c:762
#10 0x00000000006a9921 in shutdown_destructors () at /home/sjon/php-debug/php-
5.3.8/Zend/zend_execute_API.c:226
#11 0x00000000006b7747 in zend_call_destructors () at /home/sjon/php-debug/php-
5.3.8/Zend/zend.c:875
#12 0x00000000006651fd in php_request_shutdown (dummy=<optimized out>) at 
/home/sjon/php-debug/php-5.3.8/main/main.c:1594
#13 0x000000000042d105 in main (argc=2, argv=0x7fffffffebb8) at /home/sjon/php-
debug/php-5.3.8/sapi/cli/php_cli.c:1363
(gdb) frame 2
#2  0x00000000006d6009 in zend_object_std_dtor (object=0x1023dc8) at 
/home/sjon/php-debug/php-5.3.8/Zend/zend_objects.c:45
45            zend_hash_destroy(object->properties);
(gdb) print object->ce->name
$1 = 0x1025af0 "StringableObject" 
(gdb) frame 1
#1  0x00000000006c4ad8 in zend_hash_destroy (ht=0x10266d0) at /home/sjon/php-
debug/php-5.3.8/Zend/zend_hash.c:529
529                ht->pDestructor(q->pData);
(gdb) print_ht ht
[0x010266d0] {
  "test\0" => [0x01023e40] (refcount=-1) object
Program received signal SIGSEGV, Segmentation fault.
0x00000000006da0a4 in zend_object_store_get_object (zobject=0x1023e40) at 
/home/sjon/php-debug/php-5.3.8/Zend/zend_objects_API.c:272
272        return EG(objects_store).object_buckets[handle].bucket.obj.object;
The program being debugged was signaled while in a function called from GDB.
GDB remains in the frame where the signal was received.
To change this behavior use "set unwindonsignal on".
Evaluation of the expression containing the function
(zend_objects_get_address) will be abandoned.
When the function is done executing, GDB will silently stop.
(gdb) 



------------------------------------------------------------------------



-- 
Edit this bug report at https://bugs.php.net/bug.php?id=60701&edit=1

Reply via email to