Skip to content

Commit 38f1288

Browse files
committed
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.
1 parent 68fd435 commit 38f1288

File tree

3 files changed

+31
-6
lines changed

3 files changed

+31
-6
lines changed

Zend/zend_signal.c

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -330,35 +330,46 @@ void zend_signal_activate(void)
330330

331331
SIGG(active) = 1;
332332
SIGG(depth) = 0;
333+
SIGG(check) = ZEND_DEBUG;
333334
} /* }}} */
334335

335336
/* {{{ zend_signal_deactivate
336337
* */
337338
void zend_signal_deactivate(void)
338339
{
339-
340340
if (SIGG(check)) {
341341
size_t x;
342342
struct sigaction sa;
343343

344344
if (SIGG(depth) != 0) {
345345
zend_error(E_CORE_WARNING, "zend_signal: shutdown with non-zero blocking depth (%d)", SIGG(depth));
346346
}
347+
347348
/* did anyone steal our installed handler */
348349
for (x = 0; x < sizeof(zend_sigs) / sizeof(*zend_sigs); x++) {
349350
sigaction(zend_sigs[x], NULL, &sa);
350-
if (sa.sa_sigaction != zend_signal_handler_defer) {
351+
if (sa.sa_sigaction != zend_signal_handler_defer &&
352+
sa.sa_sigaction != (void *) SIG_IGN) {
351353
zend_error(E_CORE_WARNING, "zend_signal: handler was replaced for signal (%d) after startup", zend_sigs[x]);
352354
}
353355
}
354356
}
355357

356-
SIGNAL_BEGIN_CRITICAL();
357-
SIGG(active) = 0;
358+
/* After active=0 is set, signal handlers will be called directly and other
359+
* state that is reset below will not be accessed. */
360+
*((volatile int *) &SIGG(active)) = 0;
361+
358362
SIGG(running) = 0;
359363
SIGG(blocked) = 0;
360364
SIGG(depth) = 0;
361-
SIGNAL_END_CRITICAL();
365+
366+
/* If there are any queued signals because of a missed unblock, drop them. */
367+
if (SIGG(phead) && SIGG(ptail)) {
368+
SIGG(ptail)->next = SIGG(pavail);
369+
SIGG(pavail) = SIGG(phead);
370+
SIGG(phead) = NULL;
371+
SIGG(ptail) = NULL;
372+
}
362373
}
363374
/* }}} */
364375

ext/opcache/ZendAccelerator.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1570,7 +1570,9 @@ static zend_persistent_script *opcache_compile_file(zend_file_handle *file_handl
15701570

15711571
/* check blacklist right after ensuring that file was opened */
15721572
if (file_handle->opened_path && zend_accel_blacklist_is_blacklisted(&accel_blacklist, ZSTR_VAL(file_handle->opened_path))) {
1573+
SHM_UNPROTECT();
15731574
ZCSG(blacklist_misses)++;
1575+
SHM_PROTECT();
15741576
*op_array_p = accelerator_orig_compile_file(file_handle, type);
15751577
return NULL;
15761578
}
@@ -1601,7 +1603,9 @@ static zend_persistent_script *opcache_compile_file(zend_file_handle *file_handl
16011603
}
16021604

16031605
if (ZCG(accel_directives).max_file_size > 0 && size > (size_t)ZCG(accel_directives).max_file_size) {
1606+
SHM_UNPROTECT();
16041607
ZCSG(blacklist_misses)++;
1608+
SHM_PROTECT();
16051609
*op_array_p = accelerator_orig_compile_file(file_handle, type);
16061610
return NULL;
16071611
}
@@ -2003,11 +2007,16 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type)
20032007
return accelerator_orig_compile_file(file_handle, type);
20042008
}
20052009

2010+
SHM_PROTECT();
2011+
HANDLE_UNBLOCK_INTERRUPTIONS();
2012+
persistent_script = opcache_compile_file(file_handle, type, key, &op_array);
2013+
HANDLE_BLOCK_INTERRUPTIONS();
2014+
SHM_UNPROTECT();
2015+
20062016
/* Try and cache the script and assume that it is returned from_shared_memory.
20072017
* If it isn't compile_and_cache_file() changes the flag to 0
20082018
*/
20092019
from_shared_memory = 0;
2010-
persistent_script = opcache_compile_file(file_handle, type, key, &op_array);
20112020
if (persistent_script) {
20122021
persistent_script = cache_script_in_shared_memory(persistent_script, key, key ? key_length : 0, &from_shared_memory);
20132022
}

main/main.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1932,6 +1932,11 @@ void php_request_shutdown(void *dummy)
19321932
zend_unset_timeout();
19331933
} zend_end_try();
19341934

1935+
/* 17. Deactivate Zend signals */
1936+
#ifdef ZEND_SIGNALS
1937+
zend_signal_deactivate();
1938+
#endif
1939+
19351940
#ifdef PHP_WIN32
19361941
if (PG(com_initialized)) {
19371942
CoUninitialize();

0 commit comments

Comments
 (0)