fix(HandlesExprCall): this_adjust 字段偏移计算剥离 sha1 前缀
register_reexport 等继承方法调用时 ClassName 带 sha1 前缀(如 e1ea7eaf63a9c3d1.Generator),而 class_members 的 key 是裸类名 → _compute_field_byte_offset 查不到字段 → this_adjust 被跳过 → 继承方法 self 不调整 → 方法内按 ImportsGenMixin 独立布局(0-3)访问 Generator 内存错位 → ReexportSrcs 读到 null 后写 [63] 越界(ASAN 写 0x3f 崩溃)。修复:查 class_members/structs 前剥离前缀(对齐 _EnsureClassParentsLoaded 做法)。
This commit is contained in:
1 parent
7c6a497111
commit
97b714603d
1 file changed
+55
-5
@@ -2432,10 +2432,20 @@ class ExprCallHandle(BaseHandle):
|
||||
有 vtable 的类 struct 首元素为 vtable 指针(i8*),class_members 不含它。
|
||||
返回 None 表示无法计算(struct 未定义 / 字段不存在)。
|
||||
"""
|
||||
# class_members 的 key 是裸类名,而 ClassName 可能带 sha1 前缀
|
||||
# (跨模块 ObjVal 类型带前缀,如 "e1ea7eaf63a9c3d1.Generator")。
|
||||
# 不剥离则 members 为空 → 找不到字段 → this_adjust 被跳过 → 继承方法
|
||||
# self 不调整 → 运行时错位崩溃(register_reexport 写 0x3f 越界即此)。
|
||||
lookup_cls: str = ClassName
|
||||
if len(ClassName) > 17 and ClassName[16] == '.':
|
||||
lookup_cls = ClassName[17:]
|
||||
st = Gen.structs.get(ClassName)
|
||||
if (not st or not isinstance(st, ir.IdentifiedStructType) or st.elements is None) \
|
||||
and lookup_cls != ClassName:
|
||||
st = Gen.structs.get(lookup_cls)
|
||||
if not st or not isinstance(st, ir.IdentifiedStructType) or st.elements is None:
|
||||
return None
|
||||
members: list = Gen.class_members.get(ClassName, [])
|
||||
members: list = Gen.class_members.get(lookup_cls, [])
|
||||
has_vtable: bool = (ClassName in Gen.class_vtable
|
||||
or ClassName in Gen._cross_module_vtable_classes)
|
||||
base: int = 1 if has_vtable else 0
|
||||
@@ -2493,7 +2503,10 @@ class ExprCallHandle(BaseHandle):
|
||||
"""
|
||||
if method_anc is None or method_anc == ClassName:
|
||||
return ObjVal
|
||||
anc_members: list = Gen.class_members.get(method_anc, [])
|
||||
anc_lookup: str = method_anc
|
||||
if len(method_anc) > 17 and method_anc[16] == '.':
|
||||
anc_lookup = method_anc[17:]
|
||||
anc_members: list = Gen.class_members.get(anc_lookup, [])
|
||||
if not anc_members:
|
||||
return ObjVal
|
||||
first_field_name: str | None = None
|
||||
@@ -3289,15 +3302,52 @@ class ExprCallHandle(BaseHandle):
|
||||
attr_name = arg_node.attr
|
||||
len_member = f'{attr_name}__len'
|
||||
current_class = self.Trans._CurrentCpythonObjectClass
|
||||
if current_class and current_class in Gen.class_members:
|
||||
for m_name, m_type in Gen.class_members[current_class]:
|
||||
# 关键:_CurrentCpythonObjectClass 可能带 sha1 前缀(如
|
||||
# 'a351387236c6ce1c.TypeGenCType'),而 class_members /
|
||||
# class_member_element_class 的 key 全部是裸类名。必须先把前缀剥离
|
||||
# 再做 `in Gen.class_members` 检查——否则带前缀时 gate 直接 miss,
|
||||
# 整个 self.attr 分支(含 list.__len__ 修复)被跳过,fall through
|
||||
# 到 strlen(stdint.vp 0xC0000005 崩溃根因)。
|
||||
bare_cls: str | None = current_class
|
||||
if bare_cls and len(bare_cls) > 17 and bare_cls[16] == '.':
|
||||
bare_cls = bare_cls[17:]
|
||||
if bare_cls and bare_cls in Gen.class_members:
|
||||
for m_name, m_type in Gen.class_members[bare_cls]:
|
||||
if m_name == len_member:
|
||||
self_val = Gen._get_var_ptr('self')
|
||||
if self_val:
|
||||
self_ptr = Gen._load(self_val, name="self_for_len")
|
||||
offset = Gen._get_member_offset(len_member, current_class)
|
||||
offset = Gen._get_member_offset(len_member, bare_cls)
|
||||
len_ptr = Gen.builder.gep(self_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=f"self_{len_member}_ptr")
|
||||
return Gen._load(len_ptr, name=f"self_{len_member}")
|
||||
# 修复 stdint.vp 崩溃(0xC0000005)根因:`list[X] | t.CPtr` 联合字段
|
||||
# 的 LLVM 类型退化为 i8*,_HandleLenLlvm 无法识别为 list,fall through
|
||||
# 到 strlen 分支 → 对 list 对象指针执行 strlen → 垃圾长度 → 越界 get
|
||||
# → 垃圾指针 → strcmp 崩。此处按字段静态类型(class_member_element_class
|
||||
# 记录的特化名,如 'list[str]',沿 MRO 链查找含父类)分派到 list.__len__。
|
||||
field_cls: str | None = None
|
||||
_elem_map: dict = getattr(Gen, 'class_member_element_class', {})
|
||||
for _mro_cls in Gen._get_mro_chain(bare_cls):
|
||||
# class_member_element_class 的 key 是裸类名(如 'TypeGenBase'),
|
||||
# _get_mro_chain 在输入裸名时也返回裸名链;再保险剥一次前缀。
|
||||
_mro_key: str = _mro_cls
|
||||
if len(_mro_cls) > 17 and _mro_cls[16] == '.':
|
||||
_mro_key = _mro_cls[17:]
|
||||
_sub: dict = _elem_map.get(_mro_key, {})
|
||||
if attr_name in _sub:
|
||||
field_cls = _sub[attr_name]
|
||||
break
|
||||
if field_cls and (field_cls == 'list' or field_cls.startswith('list[')):
|
||||
self_val = Gen._get_var_ptr('self')
|
||||
if self_val:
|
||||
self_ptr = Gen._load(self_val, name="self_for_len")
|
||||
offset = Gen._get_member_offset(attr_name, bare_cls)
|
||||
if offset is not None:
|
||||
list_ptr = Gen.builder.gep(self_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=f"self_{attr_name}_ptr")
|
||||
list_val = Gen._load(list_ptr, name=f"self_{attr_name}")
|
||||
result = self.Trans.ExprUtils._try_operator_overLoad(field_cls, '__len__', list_val, Gen)
|
||||
if result is not None:
|
||||
return result
|
||||
val = self.HandleExprLlvm(arg_node)
|
||||
if not val:
|
||||
return None
|
||||
|
||||
Reference in new issue
Block a user