1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Add observer temporary to dl'ed functions

When observer is enabled, we normally add an extra temporary to all
functions, to store the previously observed frame. However, this is done in
zend_observer_post_startup() so it doesn't happen to dl'ed() functions.

One possible fix would be to move that from zend_observer_post_startup()
to zend_register_functions(), but this would be too early: Observer may
not be enabled when zend_register_functions() is called, and may still be
enabled later.

However, when zend_register_functions() is called at run-time (during dl()),
we know definitively whether observer is enabled.

Here I update zend_register_functions() to add a temporary to dl'ed()
functions when observer is enabled.

Fixes: GH-17211
Closes: GH-17220
This commit is contained in:
Arnaud Le Blanc
2024-12-19 19:43:00 +01:00
parent fa64a1dcd9
commit 6f579934f0
6 changed files with 95 additions and 2 deletions

3
NEWS
View File

@@ -2,6 +2,9 @@ PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ??? ????, PHP 8.2.28
- Core:
. Fixed bug GH-17211 (observer segfault on function loaded with dl()).
(Arnaud)
19 Dec 2024, PHP 8.2.27

View File

@@ -2718,7 +2718,14 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend
}
internal_function->type = ZEND_INTERNAL_FUNCTION;
internal_function->module = EG(current_module);
internal_function->T = 0;
if (EG(active) && ZEND_OBSERVER_ENABLED) {
/* Add an observer temporary to store previous observed frames. This is
* normally handled by zend_observer_post_startup(), except for
* functions registered at runtime (EG(active)). */
internal_function->T = 1;
} else {
internal_function->T = 0;
}
memset(internal_function->reserved, 0, ZEND_MAX_RESERVED_RESOURCES * sizeof(void*));
while (ptr->fname) {

View File

@@ -76,9 +76,27 @@ PHP_INI_BEGIN()
PHP_INI_END()
/* }}} */
PHP_METHOD(DlTest, test)
{
char *var = "World";
size_t var_len = sizeof("World") - 1;
zend_string *retval;
ZEND_PARSE_PARAMETERS_START(0, 1)
Z_PARAM_OPTIONAL
Z_PARAM_STRING(var, var_len)
ZEND_PARSE_PARAMETERS_END();
retval = strpprintf(0, "Hello %s", var);
RETURN_STR(retval);
}
/* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(dl_test)
{
register_class_DlTest();
/* Test backwards compatibility */
if (getenv("PHP_DL_TEST_USE_OLD_REGISTER_INI_ENTRIES")) {
zend_register_ini_entries(ini_entries, module_number);

View File

@@ -8,3 +8,7 @@
function dl_test_test1(): void {}
function dl_test_test2(string $str = ""): string {}
class DlTest {
public function test(string $str = ""): string {}
}

View File

@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 547ddbc21e9aa853b491cb17e902bbbb9cc2df00 */
* Stub hash: 2dbacf5282b0f8e53923ac70495c2da43c7237e3 */
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_dl_test_test1, 0, 0, IS_VOID, 0)
ZEND_END_ARG_INFO()
@@ -8,9 +8,12 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_dl_test_test2, 0, 0, IS_STRING,
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, str, IS_STRING, 0, "\"\"")
ZEND_END_ARG_INFO()
#define arginfo_class_DlTest_test arginfo_dl_test_test2
ZEND_FUNCTION(dl_test_test1);
ZEND_FUNCTION(dl_test_test2);
ZEND_METHOD(DlTest, test);
static const zend_function_entry ext_functions[] = {
@@ -18,3 +21,19 @@ static const zend_function_entry ext_functions[] = {
ZEND_FE(dl_test_test2, arginfo_dl_test_test2)
ZEND_FE_END
};
static const zend_function_entry class_DlTest_methods[] = {
ZEND_ME(DlTest, test, arginfo_class_DlTest_test, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
static zend_class_entry *register_class_DlTest(void)
{
zend_class_entry ce, *class_entry;
INIT_CLASS_ENTRY(ce, "DlTest", class_DlTest_methods);
class_entry = zend_register_internal_class_ex(&ce, NULL);
return class_entry;
}

View File

@@ -0,0 +1,42 @@
--TEST--
dl() / observer segfault
--EXTENSIONS--
zend_test
--SKIPIF--
<?php include dirname(__DIR__, 3) . "/dl_test/tests/skip.inc"; ?>
--INI--
zend_test.observer.enabled=1
zend_test.observer.observe_functions=1
zend_test.observer.show_output=1
--FILE--
<?php
if (PHP_OS_FAMILY === 'Windows') {
$loaded = dl('php_dl_test.dll');
} else {
$loaded = dl('dl_test.so');
}
var_dump(dl_test_test2("World!"));
$test = new DlTest();
var_dump($test->test("World!"));
?>
--EXPECTF--
<!-- init '%sgh17211.php' -->
<!-- init dl() -->
<dl>
</dl>
<!-- init dl_test_test2() -->
<dl_test_test2>
</dl_test_test2>
<!-- init var_dump() -->
<var_dump>
string(12) "Hello World!"
</var_dump>
<!-- init DlTest::test() -->
<DlTest::test>
</DlTest::test>
<var_dump>
string(12) "Hello World!"
</var_dump>