Bug #65822 [Csd]: crash on shutdown because of zend extension cleanup order

From: Date: Tue, 08 Oct 2013 15:06:26 +0000
Subject: Bug #65822 [Csd]: crash on shutdown because of zend extension cleanup order
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-182087@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=65822&edit=1

 ID:                 65822
 User updated by:    askalski at gmail dot com
 Reported by:        askalski at gmail dot com
 Summary:            crash on shutdown because of zend extension cleanup
                     order
 Status:             Closed
 Type:               Bug
 Package:            Reproducible crash
 Operating System:   Linux
 PHP Version:        5.4.20
 Assigned To:        laruence
 Block user comment: N
 Private report:     N

 New Comment:

Thanks; wasn't aware this had been fixed on APC trunk.  Just noticed now that APC has been
moved from subversion to git - this made my day.

Unaware of the already-committed fixes, I had started on a parallel development path of
configuration to disable opcode caching and interned strings.  One thing I did in my version of the
patch which you might consider:

In PHP_MINIT_FUNCTION(apc), I have it call zend_get_extension("Zend OPcache") to see if
opcache is loaded, and if so, force-disable opcode caching and interned strings.

It's a minor convenience, but could help to avoid questions in the future.


Previous Comments:
------------------------------------------------------------------------
[2013-10-08 11:20:31] laruence@php.net

actually, this is a knew issue.

and already be fixed both in opcache: https://github.com/php/php-src/commit/0aa342e903bf012efe03db1e9f1fe4ed54225e76

and apc: http://svn.php.net/viewvc?view=revision&revision=330859

please try with the latest snapshot

------------------------------------------------------------------------
[2013-10-07 18:30:24] askalski at gmail dot com

Turns out it's not so simple.  It never is...

Modules need to be shutdown before the global function/class tables are destroyed.  Extensions need
to be shutdown after.  Consequently there is no valid way to interleave extension and module
shutdown.

Because this issue likely stems from APC meddling with PHP internals in a manner in which modules
were never intended to meddle, I see no real reason to act upon this ticket... with one exception:

One thing that still ought to be fixed is zend_shutdown_extensions() should apply
zend_extension_shutdown over the zend_extensions list in *reverse* order, not forward order.  (This
would involve adding a zend_llist_reverse_apply_* family of functions to zend_llist.c)

------------------------------------------------------------------------
[2013-10-03 16:00:22] askalski at gmail dot com

Spent some time digging into this.  It's not as simple as calling zend_shutdown_extensions
before zend_destroy_modules; there are a few issues at play which complicate matters.

The two Zend Extensions I investigated (OpCache and XDebug) implement both the zend_extension and
zend_module API.  Both of these extensions load the zend_module portion by calling
zend_startup_module in the zend_extension startup function.  Also, it is possible to load modules at
runtime using the dl() userland function.

Consequently, the shutdown order is not a simple matter of "extensions first, then
modules".  Because startup order of extensions and modules can be interleaved, this precise
order must be recorded during initialization.  The implementation might be something as simple as a
stack of enumerated values: { MODULE, MODULE, MODULE, MODULE, EXTENSION, MODULE, EXTENSION, MODULE }

------------------------------------------------------------------------
[2013-10-02 22:09:12] askalski at gmail dot com

Description:
------------
php_module_startup() initializes modules first, extensions second.

However, zend_shutdown() destroys them in the same order (modules first, extensions second), rather
than in stack order as one would expect.

Furthermore, it seems (based on reading the zend_startup_extensions() zend_shutdown_extensions()
functions) that if multiple zend extensions are loaded, they are destroyed in the wrong order as
well.

Multiple modules work fine; they are destroyed in stack order.

To reproduce the issue, load an extension and module which both override the same Zend structure. 
For example, loading both OpCache 7.0.2 and APC 3.1.13 will cause a segfault on shutdown because of
improper cleanup order of orig_interned_strings_start, old_interned_strings_start, and
compiler_globals.interned_strings_start.

I'm aware that the example sounds like a bizarre combination of modules and extensions here;
I'm reporting the bug because it points at an issue in PHP itself.  The specific use case for
loading both APC and OpCache is to use OpCache for opcodes and APC with apc.cache_by_default=0 for
the apc_store/apc_fetch userland functions.


Test script:
---------------
zend_extension=/usr/lib64/php/modules/opcache.so
extension=apc.so

Load both OpCache and APC in mod_php in Apache "prefork" mode.  Send SIGTERM to one of the
workers (or simply send enough requests to make Apache reap the worker), and watch for the
Segmentation fault in Apache's error_log.


Expected result:
----------------
No crash.

Actual result:
--------------
Segmentation fault.


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



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


Thread (5 messages)

« previous php.bugs (#182087) next »