php / php/php-src

Crash when adding object to WeakMap during destruction

未关闭
#20,404 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 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

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 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

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。