Skip to content

Commit

Permalink
Fixed bug #81514
Browse files Browse the repository at this point in the history
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).
  • Loading branch information
nikic committed Oct 8, 2021
1 parent c9fb384 commit bd3e536
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 1 deletion.
2 changes: 2 additions & 0 deletions NEWS
Expand Up @@ -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).
Expand Down
18 changes: 18 additions & 0 deletions Zend/tests/enum/weak-map.phpt
@@ -0,0 +1,18 @@
--TEST--
Use enum as WeakMap key
--FILE--
<?php

enum TestEnum {
case A;
}

$map = new WeakMap();
$map[TestEnum::A] = 'a string';
var_dump($map[TestEnum::A]);
var_dump($map[TestEnum::A]);

?>
--EXPECT--
string(8) "a string"
string(8) "a string"
4 changes: 3 additions & 1 deletion Zend/zend_types.h
Expand Up @@ -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); \
Expand Down
2 changes: 2 additions & 0 deletions Zend/zend_variables.c
Expand Up @@ -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();
}
}

0 comments on commit bd3e536

Please sign in to comment.