mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
Merge branch 'PHP-8.3' into PHP-8.4
* PHP-8.3: Differenciate WeakMaps from bare HashTables used as weak maps for GC purposes
This commit is contained in:
2
NEWS
2
NEWS
@@ -7,6 +7,8 @@ PHP NEWS
|
||||
triggers "Constant already defined" warning). (ilutov)
|
||||
. Partially fixed bug GH-19542 (Scanning of string literals >=2GB will fail
|
||||
due to signed int overflow). (ilutov)
|
||||
. Fixed bug GH-19544 (GC treats ZEND_WEAKREF_TAG_MAP references as WeakMap
|
||||
references). (Arnaud, timwolla)
|
||||
|
||||
- Opcache:
|
||||
. Fixed bug GH-19493 (JIT variable not stored before YIELD). (Arnaud)
|
||||
|
||||
17
Zend/tests/gh19543-001.phpt
Normal file
17
Zend/tests/gh19543-001.phpt
Normal file
@@ -0,0 +1,17 @@
|
||||
--TEST--
|
||||
GH-19543 001: GC treats ZEND_WEAKREF_TAG_MAP references as WeakMap references
|
||||
--EXTENSIONS--
|
||||
zend_test
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$e = new Exception();
|
||||
$a = new stdClass();
|
||||
zend_weakmap_attach($e, $a);
|
||||
unset($a);
|
||||
gc_collect_cycles();
|
||||
|
||||
?>
|
||||
==DONE==
|
||||
--EXPECT--
|
||||
==DONE==
|
||||
19
Zend/tests/gh19543-002.phpt
Normal file
19
Zend/tests/gh19543-002.phpt
Normal file
@@ -0,0 +1,19 @@
|
||||
--TEST--
|
||||
GH-19543 002: GC treats ZEND_WEAKREF_TAG_MAP references as WeakMap references
|
||||
--EXTENSIONS--
|
||||
zend_test
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$e = new Exception();
|
||||
$a = new stdClass();
|
||||
zend_weakmap_attach($e, $a);
|
||||
unset($a);
|
||||
$e2 = $e;
|
||||
unset($e2); // add to roots
|
||||
gc_collect_cycles();
|
||||
|
||||
?>
|
||||
==DONE==
|
||||
--EXPECT--
|
||||
==DONE==
|
||||
@@ -36,19 +36,21 @@ typedef struct _zend_weakmap_iterator {
|
||||
uint32_t ht_iter;
|
||||
} zend_weakmap_iterator;
|
||||
|
||||
/* EG(weakrefs) is a map from a key corresponding to a zend_object pointer to all the WeakReference and/or WeakMap entries relating to that pointer.
|
||||
/* EG(weakrefs) is a map from a key corresponding to a zend_object pointer to all the WeakReference, WeakMap, and/or bare HashTable entries relating to that pointer.
|
||||
*
|
||||
* 1. For a single WeakReference,
|
||||
* the HashTable's corresponding value's tag is a ZEND_WEAKREF_TAG_REF and the pointer is a singleton WeakReference instance (zend_weakref *) for that zend_object pointer (from WeakReference::create()).
|
||||
* 2. For a single WeakMap, the HashTable's corresponding value's tag is a ZEND_WEAKREF_TAG_MAP and the pointer is a WeakMap instance (zend_weakmap *).
|
||||
* 3. For multiple values associated with the same zend_object pointer, the HashTable entry's tag is a ZEND_WEAKREF_TAG_HT with a HashTable mapping
|
||||
* tagged pointers of at most 1 WeakReference and 1 or more WeakMaps to the same tagged pointer.
|
||||
* 3. For a single bare HashTable, the HashTable's corresponding value's tag is a ZEND_WEAKREF_TAG_BARE_HT and the pointer is a HashTable*.
|
||||
* 4. For multiple values associated with the same zend_object pointer, the HashTable entry's tag is a ZEND_WEAKREF_TAG_HT with a HashTable mapping
|
||||
* tagged pointers of at most 1 WeakReference and 1 or more WeakMap or bare HashTable to the same tagged pointer.
|
||||
*
|
||||
* ZEND_MM_ALIGNED_OFFSET_LOG2 is at least 2 on supported architectures (pointers to the objects in question are aligned to 4 bytes (1<<2) even on 32-bit systems),
|
||||
* i.e. the least two significant bits of the pointer can be used as a tag (ZEND_WEAKREF_TAG_*). */
|
||||
#define ZEND_WEAKREF_TAG_REF 0
|
||||
#define ZEND_WEAKREF_TAG_MAP 1
|
||||
#define ZEND_WEAKREF_TAG_HT 2
|
||||
#define ZEND_WEAKREF_TAG_REF 0
|
||||
#define ZEND_WEAKREF_TAG_MAP 1
|
||||
#define ZEND_WEAKREF_TAG_HT 2
|
||||
#define ZEND_WEAKREF_TAG_BARE_HT 3
|
||||
#define ZEND_WEAKREF_GET_TAG(p) (((uintptr_t) (p)) & 3)
|
||||
#define ZEND_WEAKREF_GET_PTR(p) ((void *) (((uintptr_t) (p)) & ~3))
|
||||
#define ZEND_WEAKREF_ENCODE(p, t) ((void *) (((uintptr_t) (p)) | (t)))
|
||||
@@ -72,8 +74,8 @@ static inline void zend_weakref_unref_single(
|
||||
zend_weakref *wr = ptr;
|
||||
wr->referent = NULL;
|
||||
} else {
|
||||
/* unreferencing WeakMap entry (at ptr) with a key of object. */
|
||||
ZEND_ASSERT(tag == ZEND_WEAKREF_TAG_MAP);
|
||||
/* unreferencing WeakMap or bare HashTable entry (at ptr) with a key of object. */
|
||||
ZEND_ASSERT(tag == ZEND_WEAKREF_TAG_MAP || tag == ZEND_WEAKREF_TAG_BARE_HT);
|
||||
zend_hash_index_del((HashTable *) ptr, zend_object_to_weakref_key(object));
|
||||
}
|
||||
}
|
||||
@@ -166,10 +168,12 @@ static void zend_weakref_unregister(zend_object *object, void *payload, bool wea
|
||||
}
|
||||
}
|
||||
|
||||
/* Insert 'pData' into bare HashTable 'ht', with the given 'key'. 'key' is
|
||||
* weakly referenced. 'ht' is considered to be a bare HashTable, not a WeakMap. */
|
||||
ZEND_API zval *zend_weakrefs_hash_add(HashTable *ht, zend_object *key, zval *pData) {
|
||||
zval *zv = zend_hash_index_add(ht, zend_object_to_weakref_key(key), pData);
|
||||
if (zv) {
|
||||
zend_weakref_register(key, ZEND_WEAKREF_ENCODE(ht, ZEND_WEAKREF_TAG_MAP));
|
||||
zend_weakref_register(key, ZEND_WEAKREF_ENCODE(ht, ZEND_WEAKREF_TAG_BARE_HT));
|
||||
}
|
||||
return zv;
|
||||
}
|
||||
@@ -177,7 +181,7 @@ ZEND_API zval *zend_weakrefs_hash_add(HashTable *ht, zend_object *key, zval *pDa
|
||||
ZEND_API zend_result zend_weakrefs_hash_del(HashTable *ht, zend_object *key) {
|
||||
zval *zv = zend_hash_index_find(ht, zend_object_to_weakref_key(key));
|
||||
if (zv) {
|
||||
zend_weakref_unregister(key, ZEND_WEAKREF_ENCODE(ht, ZEND_WEAKREF_TAG_MAP), 1);
|
||||
zend_weakref_unregister(key, ZEND_WEAKREF_ENCODE(ht, ZEND_WEAKREF_TAG_BARE_HT), 1);
|
||||
return SUCCESS;
|
||||
}
|
||||
return FAILURE;
|
||||
@@ -540,6 +544,10 @@ HashTable *zend_weakmap_get_object_key_entry_gc(zend_object *object, zval **tabl
|
||||
ZEND_ASSERT(zv);
|
||||
zend_get_gc_buffer_add_ptr(gc_buffer, zv);
|
||||
zend_get_gc_buffer_add_obj(gc_buffer, &wm->std);
|
||||
} else if (ZEND_WEAKREF_GET_TAG(tagged_ptr) == ZEND_WEAKREF_TAG_BARE_HT) {
|
||||
/* Bare HashTables are intentionally ignored, since they are
|
||||
* intended for internal usage by extensions and might not be
|
||||
* collectable. */
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
} else if (tag == ZEND_WEAKREF_TAG_MAP) {
|
||||
@@ -548,6 +556,8 @@ HashTable *zend_weakmap_get_object_key_entry_gc(zend_object *object, zval **tabl
|
||||
ZEND_ASSERT(zv);
|
||||
zend_get_gc_buffer_add_ptr(gc_buffer, zv);
|
||||
zend_get_gc_buffer_add_obj(gc_buffer, &wm->std);
|
||||
} else if (tag == ZEND_WEAKREF_TAG_BARE_HT) {
|
||||
/* Bare HashTables are intentionally ignored (see above) */
|
||||
}
|
||||
|
||||
zend_get_gc_buffer_use(gc_buffer, table, n);
|
||||
@@ -574,6 +584,9 @@ HashTable *zend_weakmap_get_object_entry_gc(zend_object *object, zval **table, i
|
||||
zval *zv = zend_hash_index_find(&wm->ht, obj_key);
|
||||
ZEND_ASSERT(zv);
|
||||
zend_get_gc_buffer_add_ptr(gc_buffer, zv);
|
||||
} else if (ZEND_WEAKREF_GET_TAG(tagged_ptr) == ZEND_WEAKREF_TAG_BARE_HT) {
|
||||
/* Bare HashTables are intentionally ignored
|
||||
* (see zend_weakmap_get_object_key_entry_gc) */
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
} else if (tag == ZEND_WEAKREF_TAG_MAP) {
|
||||
@@ -581,6 +594,9 @@ HashTable *zend_weakmap_get_object_entry_gc(zend_object *object, zval **table, i
|
||||
zval *zv = zend_hash_index_find(&wm->ht, obj_key);
|
||||
ZEND_ASSERT(zv);
|
||||
zend_get_gc_buffer_add_ptr(gc_buffer, zv);
|
||||
} else if (tag == ZEND_WEAKREF_TAG_BARE_HT) {
|
||||
/* Bare HashTables are intentionally ignored
|
||||
* (see zend_weakmap_get_object_key_entry_gc) */
|
||||
}
|
||||
|
||||
zend_get_gc_buffer_use(gc_buffer, table, n);
|
||||
|
||||
@@ -50,7 +50,7 @@ ZEND_BEGIN_MODULE_GLOBALS(zend_test)
|
||||
int observer_fiber_switch;
|
||||
int observer_fiber_destroy;
|
||||
int observer_execute_internal;
|
||||
HashTable global_weakmap;
|
||||
HashTable *global_weakmap;
|
||||
int replace_zend_execute_ex;
|
||||
int register_passes;
|
||||
bool print_stderr_mshutdown;
|
||||
|
||||
@@ -350,7 +350,7 @@ static ZEND_FUNCTION(zend_weakmap_attach)
|
||||
Z_PARAM_ZVAL(value)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
if (zend_weakrefs_hash_add(&ZT_G(global_weakmap), obj, value)) {
|
||||
if (zend_weakrefs_hash_add(ZT_G(global_weakmap), obj, value)) {
|
||||
Z_TRY_ADDREF_P(value);
|
||||
RETURN_TRUE;
|
||||
}
|
||||
@@ -365,13 +365,13 @@ static ZEND_FUNCTION(zend_weakmap_remove)
|
||||
Z_PARAM_OBJ(obj)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
RETURN_BOOL(zend_weakrefs_hash_del(&ZT_G(global_weakmap), obj) == SUCCESS);
|
||||
RETURN_BOOL(zend_weakrefs_hash_del(ZT_G(global_weakmap), obj) == SUCCESS);
|
||||
}
|
||||
|
||||
static ZEND_FUNCTION(zend_weakmap_dump)
|
||||
{
|
||||
ZEND_PARSE_PARAMETERS_NONE();
|
||||
RETURN_ARR(zend_array_dup(&ZT_G(global_weakmap)));
|
||||
RETURN_ARR(zend_array_dup(ZT_G(global_weakmap)));
|
||||
}
|
||||
|
||||
static ZEND_FUNCTION(zend_get_current_func_name)
|
||||
@@ -1370,7 +1370,8 @@ PHP_MSHUTDOWN_FUNCTION(zend_test)
|
||||
|
||||
PHP_RINIT_FUNCTION(zend_test)
|
||||
{
|
||||
zend_hash_init(&ZT_G(global_weakmap), 8, NULL, ZVAL_PTR_DTOR, 0);
|
||||
ALLOC_HASHTABLE(ZT_G(global_weakmap));
|
||||
zend_hash_init(ZT_G(global_weakmap), 8, NULL, ZVAL_PTR_DTOR, 0);
|
||||
ZT_G(observer_nesting_depth) = 0;
|
||||
zend_test_mm_custom_handlers_rinit();
|
||||
return SUCCESS;
|
||||
@@ -1379,10 +1380,11 @@ PHP_RINIT_FUNCTION(zend_test)
|
||||
PHP_RSHUTDOWN_FUNCTION(zend_test)
|
||||
{
|
||||
zend_ulong obj_key;
|
||||
ZEND_HASH_FOREACH_NUM_KEY(&ZT_G(global_weakmap), obj_key) {
|
||||
zend_weakrefs_hash_del(&ZT_G(global_weakmap), zend_weakref_key_to_object(obj_key));
|
||||
ZEND_HASH_FOREACH_NUM_KEY(ZT_G(global_weakmap), obj_key) {
|
||||
zend_weakrefs_hash_del(ZT_G(global_weakmap), zend_weakref_key_to_object(obj_key));
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
zend_hash_destroy(&ZT_G(global_weakmap));
|
||||
zend_hash_destroy(ZT_G(global_weakmap));
|
||||
FREE_HASHTABLE(ZT_G(global_weakmap));
|
||||
|
||||
if (ZT_G(zend_test_heap)) {
|
||||
free(ZT_G(zend_test_heap));
|
||||
|
||||
Reference in New Issue
Block a user