php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #65593 Segfault when calling ob_start from output buffering callback.
Submitted: 2013-08-30 12:15 UTC Modified: 2015-02-18 12:00 UTC
Votes:3
Avg. Score:1.7 ± 0.9
Reproduced:1 of 3 (33.3%)
Same Version:0 (0.0%)
Same OS:0 (0.0%)
From: arjen at react dot com Assigned: mike
Status: Closed Package: Reproducible crash
PHP Version: 5.4Git-2013-08-30 (Git) OS: Linux
Private report: No CVE-ID:
 [2013-08-30 12:15 UTC] arjen at react dot com
Description:
------------
Unfortunately no easy to further reduce the testscript.
You have to run it using php -e to be able to reproduce it consistently. However, 
it IS possible to generate without -e.

And yes, calling ob_start from output buffer handler is stupid. We found this by 
accident :-)

Test script:
---------------
https://gist.github.com/arjenschol/6389030#file-testscript

Expected result:
----------------
No segfault, just the fatal error.

Actual result:
--------------
See https://gist.github.com/arjenschol/6389030 for a backtrace.

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2014-06-05 11:35 UTC] arjen at react dot com
This still crashes 5.5.12 (and 5.6.0beta3):

Fatal error: Cannot destroy active lambda function in /mnt/serve-a-lot_arjen/public_html/php/bug65593.php on line 12
*** Error in `/home/arjen/phpdebug/phpfarm/inst/php-5.5.12/bin/php': double free or corruption (!prev): 0x00000000013327d0 ***

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff5d03a40 in malloc_consolidate () from /usr/lib/libc.so.6
(gdb) bt
#0  0x00007ffff5d03a40 in malloc_consolidate () from /usr/lib/libc.so.6
#1  0x00007ffff5d04e14 in _int_malloc () from /usr/lib/libc.so.6
#2  0x00007ffff5d07ac7 in calloc () from /usr/lib/libc.so.6
#3  0x00007ffff7de6c37 in _dl_new_object () from /lib64/ld-linux-x86-64.so.2
#4  0x00007ffff7de2204 in _dl_map_object_from_fd () from /lib64/ld-linux-x86-64.so.2
#5  0x00007ffff7de44bb in _dl_map_object () from /lib64/ld-linux-x86-64.so.2
#6  0x00007ffff7def253 in dl_open_worker () from /lib64/ld-linux-x86-64.so.2
#7  0x00007ffff7deaf04 in _dl_catch_error () from /lib64/ld-linux-x86-64.so.2
#8  0x00007ffff7deec23 in _dl_open () from /lib64/ld-linux-x86-64.so.2
#9  0x00007ffff5da8b3d in do_dlopen () from /usr/lib/libc.so.6
#10 0x00007ffff7deaf04 in _dl_catch_error () from /lib64/ld-linux-x86-64.so.2
#11 0x00007ffff5da8bcf in dlerror_run () from /usr/lib/libc.so.6
#12 0x00007ffff5da8c41 in __libc_dlopen_mode () from /usr/lib/libc.so.6
#13 0x00007ffff5d806b5 in init () from /usr/lib/libc.so.6
#14 0x00007ffff5a78f90 in pthread_once () from /usr/lib/libpthread.so.0
#15 0x00007ffff5d807cc in backtrace () from /usr/lib/libc.so.6
#16 0x00007ffff5ca9a44 in backtrace_and_maps () from /usr/lib/libc.so.6
#17 0x00007ffff5cfdf8e in __libc_message () from /usr/lib/libc.so.6
#18 0x00007ffff5d0388e in malloc_printerr () from /usr/lib/libc.so.6
#19 0x00007ffff5d0404b in _int_free () from /usr/lib/libc.so.6
#20 0x0000000000883350 in _efree (ptr=0x13327d0, __zend_filename=0xdd5238 "/home/arjen/phpdebug/phpfarm/src/php-5.5.12/main/output.c", __zend_lineno=718, __zend_orig_filename=0x0, __zend_orig_lineno=0)
    at /home/arjen/phpdebug/phpfarm/src/php-5.5.12/Zend/zend_alloc.c:2437
#21 0x0000000000840da8 in php_output_handler_dtor (handler=0x132fb00) at /home/arjen/phpdebug/phpfarm/src/php-5.5.12/main/output.c:718
#22 0x0000000000840e6b in php_output_handler_free (h=0x132ffc0) at /home/arjen/phpdebug/phpfarm/src/php-5.5.12/main/output.c:735
#23 0x000000000083fabb in php_output_deactivate () at /home/arjen/phpdebug/phpfarm/src/php-5.5.12/main/output.c:184
#24 0x0000000000828aeb in php_request_shutdown (dummy=0x0) at /home/arjen/phpdebug/phpfarm/src/php-5.5.12/main/main.c:1783
#25 0x0000000000969caa in do_cli (argc=2, argv=0x1143060) at /home/arjen/phpdebug/phpfarm/src/php-5.5.12/sapi/cli/php_cli.c:1177
#26 0x000000000096a39d in main (argc=2, argv=0x1143060) at /home/arjen/phpdebug/phpfarm/src/php-5.5.12/sapi/cli/php_cli.c:1378
 [2014-11-19 09:13 UTC] mike@php.net
-Status: Open +Status: Feedback
 [2014-11-19 09:13 UTC] mike@php.net
Doesn't seem to be an issue anymore?
 [2014-11-19 12:22 UTC] arjen at react dot com
-Status: Feedback +Status: Open
 [2014-11-19 12:22 UTC] arjen at react dot com
php has to be compiled in debug mode:

php-5.6.3/bin/php ~/public_html/php/bug65593.php 
PHP Fatal error:  Cannot destroy active lambda function in ~/public_html/php/bug65593.php on line 12

Fatal error: Cannot destroy active lambda function in ~/public_html/php/bug65593.php on line 12
[Wed Nov 19 13:15:22 2014]  Script:  '~/public_html/php/bug65593.php'
---------------------------------------
~/phpdebug/phpfarm/src/php-5.6.3/main/output.c(717) : Block 0x7f5a1f63ad08 status:
Beginning:  	Cached
Freed (invalid)
    Start:	OK
      End:	OK
---------------------------------------
[Wed Nov 19 13:15:22 2014]  Script:  '~/public_html/php/bug65593.php'
---------------------------------------
~/phpdebug/phpfarm/src/php-5.6.3/main/output.c(718) : Block 0x7f5a1f4649c8 status:
Beginning:  	Freed
    Start:	OK
      End:	Overflown (magic=0x0000005A instead of 0x2373547F)
          	At least 4 bytes overflown
---------------------------------------


Testscript can be reduced to https://gist.github.com/arjenschol/6389030#file-test-php
 [2015-02-17 14:21 UTC] laruence@php.net
-Assigned To: +Assigned To: mike
 [2015-02-17 14:21 UTC] laruence@php.net
also exists in 5.5+
 [2015-02-17 14:29 UTC] laruence@php.net
we need a way to indicate dtor is called:

diff --git a/main/output.c b/main/output.c
index f9b8a68..34b638f 100644
--- a/main/output.c
+++ b/main/output.c
@@ -714,7 +714,13 @@ PHPAPI int php_output_handler_hook(php_output_handler_hook_t type, void *arg TSR
  * Destroy an output handler */
 PHPAPI void php_output_handler_dtor(php_output_handler *handler TSRMLS_DC)
 {
-	STR_FREE(handler->name);
+	if (handler->name) {
+		STR_FREE(handler->name);
+		handler->name = NULL; /* prevent recursively calling to this */
+	} else {
+		return;
+	}
+
 	STR_FREE(handler->buffer.data);
 	if (handler->flags & PHP_OUTPUT_HANDLER_USER) {
 		zval_ptr_dtor(&handler->func.user->zoh);
 [2015-02-18 11:32 UTC] mike@php.net
Simpler test case:

ob_start(function(){ob_start();});

The ob layer was not written with closures in mind.
Actually I faced the exact same problem in several other extensions.

@laruence, why ain't the closure just put in the GC if it cant be destroyed now?
 [2015-02-18 12:00 UTC] mike@php.net
Shouldn't the engine increase the refcount of the closure while it is executing?
 [2015-02-18 13:09 UTC] mike@php.net
Automatic comment on behalf of mike
Revision: http://git.php.net/?p=php-src.git;a=commit;h=225af964c0324b2bf14e44c0fad77198b97cc06c
Log: Fixed bug #65593 (Segfault when calling ob_start from output buffering callback)
 [2015-02-18 13:09 UTC] mike@php.net
-Status: Assigned +Status: Closed
 
PHP Copyright © 2001-2017 The PHP Group
All rights reserved.
Last updated: Wed Jul 26 04:01:41 2017 UTC