From 22dc09c9159e2daa9a10e48fd44fb9d1b2fb14ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Mon, 27 Jan 2025 09:28:06 +0100 Subject: [PATCH 1/2] Fix `#[\Deprecated]` for `__call()` and `__callStatic()` Fixes php/php-src#17597. --- NEWS | 2 ++ .../deprecated/functions/magic_call.phpt | 24 +++++++++++++++++++ Zend/zend_object_handlers.c | 7 +++++- Zend/zend_object_handlers.h | 4 ++++ 4 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 Zend/tests/attributes/deprecated/functions/magic_call.phpt diff --git a/NEWS b/NEWS index ac5d3d4c01a2d..8a81b22d9bc7d 100644 --- a/NEWS +++ b/NEWS @@ -20,6 +20,8 @@ PHP NEWS (nielsdos, ilutov) . Fix may_have_extra_named_args flag for ZEND_AST_UNPACK. (nielsdos) . Fix NULL arithmetic in System V shared memory emulation for Windows. (cmb) + . Fixed bug GH-17597 (#[\Deprecated] does not work for __call() and + __callStatic()). (timwolla) - DOM: . Fixed bug GH-17397 (Assertion failure ext/dom/php_dom.c). (nielsdos) diff --git a/Zend/tests/attributes/deprecated/functions/magic_call.phpt b/Zend/tests/attributes/deprecated/functions/magic_call.phpt new file mode 100644 index 0000000000000..b56d3a1deb716 --- /dev/null +++ b/Zend/tests/attributes/deprecated/functions/magic_call.phpt @@ -0,0 +1,24 @@ +--TEST-- +#[\Deprecated]: __call() and __callStatic() +--FILE-- +test(); +Clazz::test2(); + +?> +--EXPECTF-- +Deprecated: Method Clazz::test() is deprecated in %s + +Deprecated: Method Clazz::test2() is deprecated, due to some reason in %s on line %d diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index f08685092745a..16e2d988e6c2f 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -1617,7 +1617,12 @@ ZEND_API zend_function *zend_get_call_trampoline_func(const zend_class_entry *ce func->fn_flags = ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_PUBLIC | ZEND_ACC_VARIADIC - | (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE); + | (fbc->common.fn_flags & (ZEND_ACC_RETURN_REFERENCE|ZEND_ACC_DEPRECATED)); + if (fbc->common.attributes) { + func->attributes = zend_array_dup(fbc->common.attributes); + } else { + func->attributes = NULL; + } if (is_static) { func->fn_flags |= ZEND_ACC_STATIC; } diff --git a/Zend/zend_object_handlers.h b/Zend/zend_object_handlers.h index f36eb765c24a5..e28cad8a9600a 100644 --- a/Zend/zend_object_handlers.h +++ b/Zend/zend_object_handlers.h @@ -339,6 +339,10 @@ ZEND_API bool ZEND_FASTCALL zend_asymmetric_property_has_set_access(const zend_p } while (0) #define zend_free_trampoline(func) do { \ + if ((func)->common.attributes) { \ + zend_array_destroy((func)->common.attributes); \ + (func)->common.attributes = NULL; \ + } \ if ((func) == &EG(trampoline)) { \ EG(trampoline).common.function_name = NULL; \ } else { \ From fc92a40e694a6b3def36e9f6da2837bc32c100f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Mon, 27 Jan 2025 12:45:46 +0100 Subject: [PATCH 2/2] Do not duplicate the `attributes` table in `zend_get_call_trampoline_func()` --- Zend/zend_object_handlers.c | 3 ++- Zend/zend_object_handlers.h | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 16e2d988e6c2f..68d21d25253a4 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -1619,7 +1619,8 @@ ZEND_API zend_function *zend_get_call_trampoline_func(const zend_class_entry *ce | ZEND_ACC_VARIADIC | (fbc->common.fn_flags & (ZEND_ACC_RETURN_REFERENCE|ZEND_ACC_DEPRECATED)); if (fbc->common.attributes) { - func->attributes = zend_array_dup(fbc->common.attributes); + func->attributes = fbc->common.attributes; + GC_TRY_ADDREF(func->attributes); } else { func->attributes = NULL; } diff --git a/Zend/zend_object_handlers.h b/Zend/zend_object_handlers.h index e28cad8a9600a..2fc59d5020c25 100644 --- a/Zend/zend_object_handlers.h +++ b/Zend/zend_object_handlers.h @@ -339,11 +339,12 @@ ZEND_API bool ZEND_FASTCALL zend_asymmetric_property_has_set_access(const zend_p } while (0) #define zend_free_trampoline(func) do { \ - if ((func)->common.attributes) { \ - zend_array_destroy((func)->common.attributes); \ - (func)->common.attributes = NULL; \ + HashTable *attributes = (func)->common.attributes; \ + if (attributes && !(GC_FLAGS(attributes) & GC_IMMUTABLE) && !GC_DELREF(attributes)) { \ + zend_array_destroy(attributes); \ } \ if ((func) == &EG(trampoline)) { \ + EG(trampoline).common.attributes = NULL; \ EG(trampoline).common.function_name = NULL; \ } else { \ efree(func); \