php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #65463 SIGSEGV during zend_shutdown()
Submitted: 2013-08-17 05:46 UTC Modified: 2014-09-01 21:45 UTC
Votes:1
Avg. Score:5.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:1 (100.0%)
From: keyur@php.net Assigned: keyur
Status: Closed Package: Reproducible crash
PHP Version: 5.4.18 OS: Linux
Private report: No CVE-ID:
 [2013-08-17 05:46 UTC] keyur@php.net
Description:
------------
This issue is reproducible on PHP 5.4.13 and 5.4.18.

The configuration is: ./configure --with-apxs2 --with-config-file-path=/etc/ --
with-config-file-scan-dir=/etc/php.d

The PECL modules loaded are memcached.so (2.0.1), memcache.so (3.0.6) and 
gearman.so (1.1.1)

The test case is run via Apache httpd. The large for-loop is so one can send a 
SIGTERM while the code is executing to simulate a httpd restart mid-request. 
Once the SIGTERM is received, the Apache process seg-faults.

In the test script, one can replace the GearmanClient with any extension-defined 
class like Memcached or Memcache.

The cause is that when zend_shutdown() is called on receiving the TERM, 
zend_destroy_modules() is called 
before the GLOBAL_CLASS_TABLE is destroyed. GLOBAL_CLASS_TABLE contains the 
instance of Testing whose static member has not yet been destructed. The static 
member contains a pointer to the GearmanClient instance, which itself contains 
some pointers to functions within the extension's .so in order to self-destruct.

But since the extension .so was already unloaded by zend_destroy_modules(), when 
GLOBAL_CLASS_TABLE is 
eventually destructed, the destruct function pointer points to inaccessible 
memory and cause the process to seg-fault.

A patch is attached that fixes the order of destruction i.e. modules after 
GLOBAL_CLASS_TABLE.


Test script:
---------------
<?php

class Testing {
    static $data = array();

    function __construct() {
        $m = new GearmanClient();
        Testing::$data[] = $m;
    }
}

$c = new Testing();

for ($i=0; $i<10000000000; $i++) {
    // Loop so can attach GDB
}
echo "Hello World\n";


Expected result:
----------------
The process should exit gracefully without crashing.


Actual result:
--------------
I attached GDB and here's the stacktrace after the SIGTERM was sent:

#0  _zval_dtor_func (zvalue=0x7ffddee684b8) at /home/kgovande/php-
5.4.18/Zend/zend_variables.c:54
#1  0x00007ffde6d76a97 in _zval_dtor (zval_ptr=0x7ffdeef6fce8) at 
/home/kgovande/php-5.4.18/Zend/zend_variables.h:35
#2  _zval_ptr_dtor (zval_ptr=0x7ffdeef6fce8) at /home/kgovande/php-
5.4.18/Zend/zend_execute_API.c:436
#3  0x00007ffde6d9122b in zend_hash_destroy (ht=0x7ffdeef6a138) at 
/home/kgovande/php-5.4.18/Zend/zend_hash.c:560
#4  0x00007ffde6d834ab in _zval_dtor_func (zvalue=0x7ffdeef6a190) at 
/home/kgovande/php-5.4.18/Zend/zend_variables.c:45
#5  0x00007ffde6d76a97 in _zval_dtor (zval_ptr=0x7ffdeef680b0) at 
/home/kgovande/php-5.4.18/Zend/zend_variables.h:35
#6  _zval_ptr_dtor (zval_ptr=0x7ffdeef680b0) at /home/kgovande/php-
5.4.18/Zend/zend_execute_API.c:436
#7  0x00007ffde6d7b1ff in destroy_zend_class (pce=<value optimized out>) at 
/home/kgovande/php-5.4.18/Zend/zend_opcode.c:289
#8  0x00007ffde6d9122b in zend_hash_destroy (ht=0x7ffdf00679c0) at 
/home/kgovande/php-5.4.18/Zend/zend_hash.c:560
#9  0x00007ffde6d84a3d in zend_shutdown () at /home/kgovande/php-
5.4.18/Zend/zend.c:823
#10 0x00007ffde6d277ba in php_module_shutdown () at /home/kgovande/php-
5.4.18/main/main.c:2370
#11 0x00007ffde6d27879 in php_module_shutdown_wrapper (sapi_globals=<value 
optimized out>) at /home/kgovande/php-5.4.18/main/main.c:2338
#12 0x00007ffde6e2d1d1 in php_apache_child_shutdown (tmp=<value optimized out>) 
at /home/kgovande/php-5.4.18/sapi/apache2handler/sapi_apache2.c:398
#13 0x00007ffdedafa99e in run_cleanups (pool=0x7ffdf025a1f8) at 
memory/unix/apr_pools.c:2314
#14 apr_pool_destroy (pool=0x7ffdf025a1f8) at memory/unix/apr_pools.c:782
#15 0x00007ffdef03548e in clean_child_exit (code=0) at /usr/src/debug/httpd-
2.2.15/server/mpm/prefork/prefork.c:196
#16 0x00007ffdef035b7b in just_die (sig=<value optimized out>) at 
/usr/src/debug/httpd-2.2.15/server/mpm/prefork/prefork.c:328
#17 <signal handler called>
#18 zval_refcount_p (execute_data=0x7ffdeef322c8) at /home/kgovande/php-
5.4.18/Zend/zend.h:383
#19 ZEND_POST_INC_SPEC_CV_HANDLER (execute_data=0x7ffdeef322c8) at 
/home/kgovande/php-5.4.18/Zend/zend_vm_execute.h:26699
#20 0x00007ffde6deca10 in execute (op_array=0x7ffdeef6fb28) at 
/home/kgovande/php-5.4.18/Zend/zend_vm_execute.h:410
#21 0x00007ffde6d837dd in zend_execute_scripts (type=8, retval=0x0, 
file_count=3) at /home/kgovande/php-5.4.18/Zend/zend.c:1315
#22 0x00007ffde6d275a7 in php_execute_script (primary_file=0x7fffec067c90) at 
/home/kgovande/php-5.4.18/main/main.c:2497
#23 0x00007ffde6e2e385 in php_handler (r=0x7ffdf02682e8) at /home/kgovande/php-
5.4.18/sapi/apache2handler/sapi_apache2.c:667
#24 0x00007ffdef021b00 in ap_run_handler (r=0x7ffdf02682e8) at 
/usr/src/debug/httpd-2.2.15/server/config.c:158
#25 0x00007ffdef0253be in ap_invoke_handler (r=0x7ffdf02682e8) at 
/usr/src/debug/httpd-2.2.15/server/config.c:376
#26 0x00007ffdef030a30 in ap_process_request (r=0x7ffdf02682e8) at 
/usr/src/debug/httpd-2.2.15/modules/http/http_request.c:282
#27 0x00007ffdef02d8f8 in ap_process_http_connection (c=0x7ffdf025c478) at 
/usr/src/debug/httpd-2.2.15/modules/http/http_core.c:190
#28 0x00007ffdef029608 in ap_run_process_connection (c=0x7ffdf025c478) at 
/usr/src/debug/httpd-2.2.15/server/connection.c:43
#29 0x00007ffdef035807 in child_main (child_num_arg=<value optimized out>) at 
/usr/src/debug/httpd-2.2.15/server/mpm/prefork/prefork.c:667
#30 0x00007ffdef035b1a in make_child (s=0x7ffdefc65860, slot=0) at 
/usr/src/debug/httpd-2.2.15/server/mpm/prefork/prefork.c:763
#31 0x00007ffdef035e4b in startup_children (_pconf=<value optimized out>, plog=
<value optimized out>, s=<value optimized out>) at /usr/src/debug/httpd-
2.2.15/server/mpm/prefork/prefork.c:781
#32 ap_mpm_run (_pconf=<value optimized out>, plog=<value optimized out>, s=
<value optimized out>) at /usr/src/debug/httpd-
2.2.15/server/mpm/prefork/prefork.c:1002
#33 0x00007ffdef00d900 in main (argc=1, argv=0x7fffec068258) at 
/usr/src/debug/httpd-2.2.15/server/main.c:760


Patches

php-segv (last revision 2013-09-04 18:52 UTC) by keyur@php.net)

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2013-08-17 05:46 UTC] keyur@php.net
The following patch has been added/updated:

Patch Name: php-segv
Revision:   1376718387
URL:        https://bugs.php.net/patch-display.php?bug=65463&patch=php-segv&revision=1376718387
 [2013-09-04 18:52 UTC] keyur@php.net
The following patch has been added/updated:

Patch Name: php-segv
Revision:   1378320776
URL:        https://bugs.php.net/patch-display.php?bug=65463&patch=php-segv&revision=1378320776
 [2013-09-04 18:57 UTC] keyur@php.net
Modified the patch slightly. The order of destruction of the modules v. the 
GLOBAL_* is important. The module may have pointers into the GLOBAL_FUNCTION_TABLE 
and if the GLOBAL_FUNCTION_TABLE is destructed first, then the pointers inside the 
module are now dangling.

This is only an issue in --enable-debug mode, when the HashTables's are checked to 
ensure they weren't already destructed.
 [2014-09-01 21:45 UTC] keyur@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: keyur
 [2014-09-01 21:45 UTC] keyur@php.net
The fix for this bug has been committed.

Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.

 For Windows:

http://windows.php.net/snapshots/
 
Thank you for the report, and for helping us make PHP better.


 
PHP Copyright © 2001-2017 The PHP Group
All rights reserved.
Last updated: Wed Feb 22 22:01:36 2017 UTC