Crash when adding object to WeakMap during destruction
未关闭
还没有人认领这个 Issue。
Bug
Status: Verified
- 主要语言
- C
- 星标
- 40.4k
- 派生
- 8.1k
- 平均合并
- 2 天 13 小时
- 30 天内合并 PR
- 96
描述
Description
The following code (simplified reproducer):
<?php
$w = new WeakMap;
$o = new stdClass;
$w[$o] = new class($r) {
function __construct(public &$r) {}
function __destruct() {
global $refs;
$o = $this->r->get();
for ($i = 0; $i < 8; ++$i) {
$r = new WeakMap;
$r[$o] = 1;
$refs[] = $r;
}
}
};
$r = WeakReference::create($o);
Resulted in this output:
==36773== Invalid read of size 1
==36773== at 0x55C8198: zval_get_type (zend_types.h:648)
==36773== by 0x55C78E7: zend_weakref_unref (/usr/local/src/php/Zend/zend_weakrefs.c:86)
==36773== by 0x55C7783: zend_weakrefs_notify (/usr/local/src/php/Zend/zend_weakrefs.c:201)
==36773== by 0x55DFDAF: zend_object_std_dtor (/usr/local/src/php/Zend/zend_objects.c:54)
==36773== by 0x55EA76F: zend_objects_store_del (/usr/local/src/php/Zend/zend_objects_API.c:200)
==36773== by 0x5499757: rc_dtor_func (/usr/local/src/php/Zend/zend_variables.c:57)
==36773== by 0x54997F3: i_zval_ptr_dtor (zend_variables.h:44)
==36773== by 0x5499793: zval_ptr_dtor (/usr/local/src/php/Zend/zend_variables.c:84)
==36773== by 0x54BE46F: _zend_hash_del_el_ex (/usr/local/src/php/Zend/zend_hash.c:1488)
==36773== by 0x54BDF6B: _zend_hash_del_el (/usr/local/src/php/Zend/zend_hash.c:1515)
==36773== by 0x54C15C3: zend_hash_reverse_apply (/usr/local/src/php/Zend/zend_hash.c:2231)
==36773== by 0x547A843: shutdown_destructors (/usr/local/src/php/Zend/zend_execute_API.c:260)
==36773== Address 0xe812a58 is 104 bytes inside a block of size 320 free'd
==36773== at 0x604B614: free (m_replacemalloc/vg_replace_malloc.c:989)
==36773== by 0x544D673: _efree_custom (/usr/local/src/php/Zend/zend_alloc.c:2500)
==36773== by 0x544D5C7: _efree (/usr/local/src/php/Zend/zend_alloc.c:2620)
==36773== by 0x54C5D4F: zend_hash_do_resize (/usr/local/src/php/Zend/zend_hash.c:1316)
==36773== by 0x54BD157: _zend_hash_index_add_or_update_i (/usr/local/src/php/Zend/zend_hash.c:1163)
==36773== by 0x54BCACB: zend_hash_index_add_new (/usr/local/src/php/Zend/zend_hash.c:1211)
==36773== by 0x55CA1EB: zend_hash_index_add_new_ptr (zend_hash.h:808)
==36773== by 0x55C729F: zend_weakref_register (/usr/local/src/php/Zend/zend_weakrefs.c:110)
==36773== by 0x55C9317: zend_weakmap_write_dimension (/usr/local/src/php/Zend/zend_weakrefs.c:385)
==36773== by 0x5598AFB: zend_assign_to_object_dim (/usr/local/src/php/Zend/zend_execute.c:1535)
==36773== by 0x55039EF: ZEND_ASSIGN_DIM_SPEC_CV_CV_OP_DATA_CONST_HANDLER (zend_vm_execute.h:51937)
==36773== by 0x54E2073: execute_ex (zend_vm_execute.h:57037)
==36773== Block was alloc'd at
==36773== at 0x60485D4: malloc (m_replacemalloc/vg_replace_malloc.c:446)
==36773== by 0x544DA1B: __zend_malloc (/usr/local/src/php/Zend/zend_alloc.c:3128)
==36773== by 0x544D54F: _malloc_custom (/usr/local/src/php/Zend/zend_alloc.c:2491)
==36773== by 0x544D493: _emalloc (/usr/local/src/php/Zend/zend_alloc.c:2610)
==36773== by 0x54B8887: zend_hash_real_init_mixed_ex (/usr/local/src/php/Zend/zend_hash.c:177)
==36773== by 0x54B8787: zend_hash_real_init_mixed (/usr/local/src/php/Zend/zend_hash.c:343)
==36773== by 0x54BD06F: _zend_hash_index_add_or_update_i (/usr/local/src/php/Zend/zend_hash.c:1150)
==36773== by 0x54BCACB: zend_hash_index_add_new (/usr/local/src/php/Zend/zend_hash.c:1211)
==36773== by 0x55CA1EB: zend_hash_index_add_new_ptr (zend_hash.h:808)
==36773== by 0x55C72F3: zend_weakref_register (/usr/local/src/php/Zend/zend_weakrefs.c:117)
==36773== by 0x55C8057: zend_weakref_create (/usr/local/src/php/Zend/zend_weakrefs.c:253)
==36773== by 0x55C7CA7: zim_WeakReference_create (/usr/local/src/php/Zend/zend_weakrefs.c:291)
I.e. the cleanup in zend_weakref_unref() is not compatible with modifications during unref.
PHP Version
PHP 8.2+
Operating System
No response
贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
调研方向
从 reproducer 开始,检查 zend_weakrefs.c 中的 zend_weakref_unref() 以及相关的注册和通知路径;使用 Valgrind trace 跟踪销毁期间的无效读取。当在销毁期间添加 WeakMap 条目时,reproducer 不再报告无效读取,即表示完成。
由索引模型根据 Issue 内容生成。
评估
- 技术栈
- c, php
- 领域
- backend
- Issue 类型
- 缺陷
- 难度
- 4/5
- 预计耗时
- 3-5 天
- 活跃度
- 停滞
- 描述清晰度
- 描述清楚
- 新手友好度
- 45/100