From bd3e5363836df9c7d05b74f6c7bc53ccc145c535 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 8 Oct 2021 10:31:24 +0200 Subject: [PATCH] Fixed bug #81514 Objects reuse the GC_PERSISTENT flag as IS_OBJ_WEAKLY_REFERENCED, which we did not account for in ZVAL_COPY_OR_DUP. To make things worse the incorrect zval_copy_ctor_func() invocation silently did nothing. To avoid that, add an assertion that it should only be called with arrays and strings (unlike the normal zval_copy_ctor() which can be safely called on any zval). --- NEWS | 2 ++ Zend/tests/enum/weak-map.phpt | 18 ++++++++++++++++++ Zend/zend_types.h | 4 +++- Zend/zend_variables.c | 2 ++ 4 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 Zend/tests/enum/weak-map.phpt diff --git a/NEWS b/NEWS index e515455be10..2db0ec4eaff 100644 --- a/NEWS +++ b/NEWS @@ -9,6 +9,8 @@ PHP NEWS . Fixed bug #75941 (Fix compile failure on Solaris with clang). (Jaromír Doleček) . Fixed bug #81380 (Observer may not be initialized properly). (krakjoe) + . Fixed bug #81514 (Using Enum as key in WeakMap triggers GC + SegFault). + (Nikita) - Date: . Fixed bug #81504 (Incorrect timezone transition details for POSIX data). diff --git a/Zend/tests/enum/weak-map.phpt b/Zend/tests/enum/weak-map.phpt new file mode 100644 index 00000000000..a8cb51bc46a --- /dev/null +++ b/Zend/tests/enum/weak-map.phpt @@ -0,0 +1,18 @@ +--TEST-- +Use enum as WeakMap key +--FILE-- + +--EXPECT-- +string(8) "a string" +string(8) "a string" diff --git a/Zend/zend_types.h b/Zend/zend_types.h index fe551c38820..4a1232198fc 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -1286,7 +1286,9 @@ static zend_always_inline uint32_t zval_delref_p(zval* pz) { uint32_t _t = Z_TYPE_INFO_P(_z2); \ ZVAL_COPY_VALUE_EX(_z1, _z2, _gc, _t); \ if (Z_TYPE_INFO_REFCOUNTED(_t)) { \ - if (EXPECTED(!(GC_FLAGS(_gc) & GC_PERSISTENT))) { \ + /* Objects reuse PERSISTENT as WEAKLY_REFERENCED */ \ + if (EXPECTED(!(GC_FLAGS(_gc) & GC_PERSISTENT) \ + || GC_TYPE(_gc) == IS_OBJECT)) { \ GC_ADDREF(_gc); \ } else { \ zval_copy_ctor_func(_z1); \ diff --git a/Zend/zend_variables.c b/Zend/zend_variables.c index 810866a1be2..06483d581df 100644 --- a/Zend/zend_variables.c +++ b/Zend/zend_variables.c @@ -129,5 +129,7 @@ ZEND_API void ZEND_FASTCALL zval_copy_ctor_func(zval *zvalue) ZEND_ASSERT(!ZSTR_IS_INTERNED(Z_STR_P(zvalue))); CHECK_ZVAL_STRING(Z_STR_P(zvalue)); ZVAL_NEW_STR(zvalue, zend_string_dup(Z_STR_P(zvalue), 0)); + } else { + ZEND_UNREACHABLE(); } }