From e6378916b94be2426205c4e87d3d438d573dc114 Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Sat, 4 Apr 2026 07:44:52 -0400 Subject: [PATCH 1/2] Fix GH-16811: Crash in zend_test observer on runtime observe_function_names change OnUpdateCommaList called zend_observer_remove/add_begin_handler without checking whether observer data was initialized. This null-dereferenced when the function had never been called (no runtime cache), and hit ZEND_UNREACHABLE() when observe_all had already installed the same handler. Guard both the remove and add blocks with runtime cache checks. Remove existing handlers before re-adding to prevent slot overflow from duplicates. Closes GH-16811 --- ext/zend_test/observer.c | 9 +++++++-- ext/zend_test/tests/gh16811.phpt | 17 +++++++++++++++++ ext/zend_test/tests/gh16811_observe_all.phpt | 17 +++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 ext/zend_test/tests/gh16811.phpt create mode 100644 ext/zend_test/tests/gh16811_observe_all.phpt diff --git a/ext/zend_test/observer.c b/ext/zend_test/observer.c index 85c7d82da0e84..e348987359b91 100644 --- a/ext/zend_test/observer.c +++ b/ext/zend_test/observer.c @@ -334,7 +334,8 @@ static ZEND_INI_MH(zend_test_observer_OnUpdateCommaList) } if (stage != PHP_INI_STAGE_STARTUP && stage != PHP_INI_STAGE_ACTIVATE && stage != PHP_INI_STAGE_DEACTIVATE && stage != PHP_INI_STAGE_SHUTDOWN) { ZEND_HASH_FOREACH_STR_KEY(*p, funcname) { - if ((func = zend_hash_find_ptr(EG(function_table), funcname))) { + if ((func = zend_hash_find_ptr(EG(function_table), funcname)) + && RUN_TIME_CACHE(&func->common)) { void *old_handler; zend_observer_remove_begin_handler(func, observer_begin, (zend_observer_fcall_begin_handler *)&old_handler); zend_observer_remove_end_handler(func, observer_end, (zend_observer_fcall_end_handler *)&old_handler); @@ -357,7 +358,11 @@ static ZEND_INI_MH(zend_test_observer_OnUpdateCommaList) zend_string_release(str); if (stage != PHP_INI_STAGE_STARTUP && stage != PHP_INI_STAGE_ACTIVATE && stage != PHP_INI_STAGE_DEACTIVATE && stage != PHP_INI_STAGE_SHUTDOWN) { ZEND_HASH_FOREACH_STR_KEY(*p, funcname) { - if ((func = zend_hash_find_ptr(EG(function_table), funcname))) { + if ((func = zend_hash_find_ptr(EG(function_table), funcname)) + && RUN_TIME_CACHE(&func->common) && *ZEND_OBSERVER_DATA(func)) { + void *old_handler; + zend_observer_remove_begin_handler(func, observer_begin, (zend_observer_fcall_begin_handler *)&old_handler); + zend_observer_remove_end_handler(func, observer_end, (zend_observer_fcall_end_handler *)&old_handler); zend_observer_add_begin_handler(func, observer_begin); zend_observer_add_end_handler(func, observer_end); } diff --git a/ext/zend_test/tests/gh16811.phpt b/ext/zend_test/tests/gh16811.phpt new file mode 100644 index 0000000000000..da05774ac5941 --- /dev/null +++ b/ext/zend_test/tests/gh16811.phpt @@ -0,0 +1,17 @@ +--TEST-- +GH-16811 (Segmentation fault in zend observer) +--EXTENSIONS-- +zend_test +--INI-- +zend_test.observer.enabled=1 +zend_test.observer.observe_function_names=a,d +--FILE-- + +--EXPECTF-- + + + +string(3) "a,d" diff --git a/ext/zend_test/tests/gh16811_observe_all.phpt b/ext/zend_test/tests/gh16811_observe_all.phpt new file mode 100644 index 0000000000000..466aa0c6d4a4f --- /dev/null +++ b/ext/zend_test/tests/gh16811_observe_all.phpt @@ -0,0 +1,17 @@ +--TEST-- +GH-16811 (Assertion failure adding duplicate observer handler) +--EXTENSIONS-- +zend_test +--INI-- +zend_test.observer.enabled=1 +zend_test.observer.observe_all=1 +zend_test.observer.show_output=0 +--FILE-- + +--EXPECT-- +Done From cdf733a8100fad0af0e21c03cb510f608298a779 Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Sat, 4 Apr 2026 17:59:13 -0400 Subject: [PATCH 2/2] Fix gh16811.phpt on CircleCI ARM CircleCI ARM passes -d zend_test.observer.show_output=0 globally. The test relied on the default (1) instead of setting it explicitly, so the lines were suppressed. --- ext/zend_test/tests/gh16811.phpt | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/zend_test/tests/gh16811.phpt b/ext/zend_test/tests/gh16811.phpt index da05774ac5941..1b2b8ece9aa1a 100644 --- a/ext/zend_test/tests/gh16811.phpt +++ b/ext/zend_test/tests/gh16811.phpt @@ -4,6 +4,7 @@ GH-16811 (Segmentation fault in zend observer) zend_test --INI-- zend_test.observer.enabled=1 +zend_test.observer.show_output=1 zend_test.observer.observe_function_names=a,d --FILE--