diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2019-07-23 10:38:23 +0200 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2019-07-29 15:17:32 +0200 |
commit | 38f1288b6427fc9e2fa2b5ad9912745ded923ee7 (patch) | |
tree | 65df8f768367df986838b6dc72dfd7a33ee59c79 /Zend | |
parent | 68fd435ba81e0208d30218b0558cccbf76b85e49 (diff) | |
download | php-git-38f1288b6427fc9e2fa2b5ad9912745ded923ee7.tar.gz |
Fix Zend signals unblocking
There are a few parts here:
* opcache should not be blocking signals while invoking compile_file,
otherwise signals may remain blocked on a compile error. While at
it, also protect SHM memory during compile_file.
* We should deactivate Zend signals at the end of the request, to make
sure that we gracefully recover from a missing unblock and signals
don't remain blocked forever.
* We don't use a critical section in deactivation, because it should
not be necessary. Additionally we want to clean up the signal queue,
if it is non-empty.
* Enable SIGG(check) in debug builds so we notice issues in the future.
Diffstat (limited to 'Zend')
-rw-r--r-- | Zend/zend_signal.c | 21 |
1 files changed, 16 insertions, 5 deletions
diff --git a/Zend/zend_signal.c b/Zend/zend_signal.c index 1cfab63eee..f43de50b64 100644 --- a/Zend/zend_signal.c +++ b/Zend/zend_signal.c @@ -330,13 +330,13 @@ void zend_signal_activate(void) SIGG(active) = 1; SIGG(depth) = 0; + SIGG(check) = ZEND_DEBUG; } /* }}} */ /* {{{ zend_signal_deactivate * */ void zend_signal_deactivate(void) { - if (SIGG(check)) { size_t x; struct sigaction sa; @@ -344,21 +344,32 @@ void zend_signal_deactivate(void) if (SIGG(depth) != 0) { zend_error(E_CORE_WARNING, "zend_signal: shutdown with non-zero blocking depth (%d)", SIGG(depth)); } + /* did anyone steal our installed handler */ for (x = 0; x < sizeof(zend_sigs) / sizeof(*zend_sigs); x++) { sigaction(zend_sigs[x], NULL, &sa); - if (sa.sa_sigaction != zend_signal_handler_defer) { + if (sa.sa_sigaction != zend_signal_handler_defer && + sa.sa_sigaction != (void *) SIG_IGN) { zend_error(E_CORE_WARNING, "zend_signal: handler was replaced for signal (%d) after startup", zend_sigs[x]); } } } - SIGNAL_BEGIN_CRITICAL(); - SIGG(active) = 0; + /* After active=0 is set, signal handlers will be called directly and other + * state that is reset below will not be accessed. */ + *((volatile int *) &SIGG(active)) = 0; + SIGG(running) = 0; SIGG(blocked) = 0; SIGG(depth) = 0; - SIGNAL_END_CRITICAL(); + + /* If there are any queued signals because of a missed unblock, drop them. */ + if (SIGG(phead) && SIGG(ptail)) { + SIGG(ptail)->next = SIGG(pavail); + SIGG(pavail) = SIGG(phead); + SIGG(phead) = NULL; + SIGG(ptail) = NULL; + } } /* }}} */ |