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