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