diff --git a/ext/dl_test/dl_test.stub.php b/ext/dl_test/dl_test.stub.php index 4f5a445e9837..24ca1d323b41 100644 --- a/ext/dl_test/dl_test.stub.php +++ b/ext/dl_test/dl_test.stub.php @@ -20,6 +20,7 @@ public function test(string $str = ""): string {} class DlTestSuperClass { public int $a; + public int $temporary = 0; public function test(string $str = ""): string {} } diff --git a/ext/dl_test/dl_test_arginfo.h b/ext/dl_test/dl_test_arginfo.h index bd7752211150..323bd1d8028e 100644 --- a/ext/dl_test/dl_test_arginfo.h +++ b/ext/dl_test/dl_test_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 0ab7bc0f3289a77ecb1850a1cc7056b7c5297fda */ + * Stub hash: 41b8200735b71e691dc431d7ce34e9e0b9a4a7fd */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_dl_test_test1, 0, 0, IS_VOID, 0) ZEND_END_ARG_INFO() @@ -69,6 +69,12 @@ static zend_class_entry *register_class_DlTestSuperClass(void) zend_declare_typed_property(class_entry, property_a_name, &property_a_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(property_a_name); + zval property_temporary_default_value; + ZVAL_LONG(&property_temporary_default_value, 0); + zend_string *property_temporary_name = zend_string_init("temporary", sizeof("temporary") - 1, 1); + zend_declare_typed_property(class_entry, property_temporary_name, &property_temporary_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(property_temporary_name); + return class_entry; } diff --git a/ext/dl_test/tests/opcache_temporary_strings.inc b/ext/dl_test/tests/opcache_temporary_strings.inc new file mode 100644 index 000000000000..2da8426961cd --- /dev/null +++ b/ext/dl_test/tests/opcache_temporary_strings.inc @@ -0,0 +1,16 @@ +getMessage(), PHP_EOL; +} + +try { + (new DlTest)->test([]); +} catch (TypeError $e) { + echo $e::class, ": ", $e->getMessage(), PHP_EOL; +} + +var_dump((new ReflectionFunction('dl_test_test2'))->getName()); + +var_dump(get_object_vars(new DlTestSubClass)); diff --git a/ext/dl_test/tests/opcache_temporary_strings.phpt b/ext/dl_test/tests/opcache_temporary_strings.phpt new file mode 100644 index 000000000000..e51a2b7247ca --- /dev/null +++ b/ext/dl_test/tests/opcache_temporary_strings.phpt @@ -0,0 +1,22 @@ +--TEST-- +dl() under opcache: refcounting names declared by a temporary module +--SKIPIF-- + +--EXTENSIONS-- +opcache +--INI-- +enable_dl=1 +opcache.enable_cli=1 +--FILE-- + +--EXPECT-- +TypeError: dl_test_test2(): Argument #1 ($str) must be of type string, array given +TypeError: DlTest::test(): Argument #1 ($str) must be of type string, array given +string(13) "dl_test_test2" +array(1) { + ["temporary"]=> + int(0) +} diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index 79c7668ba5e9..7d35ef5c147b 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -578,6 +578,13 @@ static zend_string* ZEND_FASTCALL accel_new_interned_string_for_php(zend_string return ret; } } +#if ZEND_RC_DEBUG + /* PHP shouldn't create persistent strings during request, but at least + * dl() may do this. They belong to the temporary module and are not shared. */ + if (!zend_rc_debug && !ZSTR_IS_INTERNED(str) && (GC_FLAGS(str) & GC_PERSISTENT)) { + GC_MAKE_PERSISTENT_LOCAL(str); + } +#endif return str; } @@ -602,19 +609,31 @@ static zend_always_inline zend_string *accel_find_interned_string_ex(zend_ulong static zend_string* ZEND_FASTCALL accel_init_interned_string_for_php(const char *str, size_t size, bool permanent) { + zend_string *ret; + if (ZCG(counted)) { zend_ulong h = zend_inline_hash_func(str, size); - zend_string *ret = accel_find_interned_string_ex(h, str, size); + ret = accel_find_interned_string_ex(h, str, size); - if (!ret) { - ret = zend_string_init(str, size, permanent); - ZSTR_H(ret) = h; + if (ret) { + return ret; } - return ret; + ret = zend_string_init(str, size, permanent); + ZSTR_H(ret) = h; + } else { + ret = zend_string_init(str, size, permanent); } - return zend_string_init(str, size, permanent); +#if ZEND_RC_DEBUG + /* PHP shouldn't create persistent strings during request, but at least + * dl() may do this. They belong to the temporary module and are not shared. */ + if (!zend_rc_debug && permanent) { + GC_MAKE_PERSISTENT_LOCAL(ret); + } +#endif + + return ret; } static inline void accel_copy_permanent_list_types(