diff --git a/lib/core/Handles/HandlesClassDef.py b/lib/core/Handles/HandlesClassDef.py index d7d7723..21d9bb6 100644 --- a/lib/core/Handles/HandlesClassDef.py +++ b/lib/core/Handles/HandlesClassDef.py @@ -613,26 +613,34 @@ class ClassHandle(BaseHandle): Gen.class_parents[ClassName] = ParentClasses if ParentClasses: # ============================================================ - # 多继承字段展平:遍历所有父类(声明顺序),字段名去重(先声明父类优先), + # 多继承字段展平:遍历所有父类(声明顺序),字段名**不去重**, # __vtable__ 跳过(vtable 指针由 _generate_structs 按 class_vtable 统一添加)。 - # 布局: [父类1字段..., 父类2字段..., 子类字段...] + # 布局: [父类1字段..., 父类2字段..., 子类字段...](MRO 正序,与 + # DeclarationGenerator stub / TPV 参考实现一致)。 + # + # 关键修复(2026-08-10):原实现用 `inherited + class_members`(prepend) + # 产出 MRO 反序布局,且按字段名去重(如多个 Mixin 各自声明的 TempDir + # 被剔除)——导致定义模块 struct 与跨模块 stub 布局不一致,所有多继承 + # 类字段运行时错位(ASan 下读到 0xbe 填充崩溃)。Mixin 方法体以自身 + # 局部索引独立编译,调用侧 this_adjust + 块内索引依赖"展平块与 Mixin + # 自身逐字段一致",因此跨父类不能去重。菱形继承(A→D, B→D)会让 D + # 字段重复——当前项目 Mixin 为兄弟无共享祖先;若未来出现真菱形需改为 + # "按继承源去重"而非"按字段名去重"。 # ============================================================ for ParentClass in ParentClasses: if ParentClass not in class_graph and ParentClass not in Gen.class_members: continue parent_members: list = list(Gen.class_members.get(ParentClass, [])) parent_defaults: dict = dict(Gen.class_member_defaults.get(ParentClass, {})) - existing_names: set = {m[0] for m in Gen.class_members[ClassName]} inherited: list[tuple] = [] for pm_name, pm_type in parent_members: if pm_name == '__vtable__': continue - if pm_name not in existing_names: - inherited.append((pm_name, pm_type)) - if pm_name in parent_defaults: - Gen.class_member_defaults[ClassName][pm_name] = parent_defaults[pm_name] + inherited.append((pm_name, pm_type)) + if pm_name in parent_defaults: + Gen.class_member_defaults[ClassName][pm_name] = parent_defaults[pm_name] if inherited: - Gen.class_members[ClassName] = inherited + Gen.class_members[ClassName] + Gen.class_members[ClassName] = Gen.class_members[ClassName] + inherited # ============================================================ # 多继承方法合并:遍历所有父类(声明顺序)收集方法(短名去重,先声明父类优先), # vtable 槽/方法名用"实际定义类.方法"(如 B.get_b,与 TPV 一致), diff --git a/lib/core/Handles/HandlesImports.py b/lib/core/Handles/HandlesImports.py index 6058d6e..dc95aee 100644 --- a/lib/core/Handles/HandlesImports.py +++ b/lib/core/Handles/HandlesImports.py @@ -1852,6 +1852,7 @@ class ImportHandle(BaseHandle): # 避免 struct body 从不完整 class_members 生成导致 GEP 越界。 # 同时处理父类 class_members 全为占位符的情况(清除后重新加载)。 _any_parent_loaded: bool = False + _all_inherited: list[tuple] = [] for _ParentClass in _ParentClasses: if not _ParentClass: continue @@ -1882,18 +1883,30 @@ class ImportHandle(BaseHandle): if _ParentClass in Gen.class_members: _parent_members: list = list(Gen.class_members[_ParentClass]) _parent_defaults: dict = dict(Gen.class_member_defaults.get(_ParentClass, {})) - _existing_names: set = {m[0] for m in Gen.class_members[ClassName]} - _inherited: list[tuple] = [] + # 跨父类不去重(与 HandlesClassDef 展平、DeclarationGenerator stub 一致): + # 多继承展平必须保留每个父类全部字段(含重名如多个 Mixin 的 TempDir), + # 否则 Mixin 方法体 this_adjust + 块内局部索引寻址与全量布局错位。 for _pm_name, _pm_type in _parent_members: if _pm_name == '__vtable__': continue - if _pm_name not in _existing_names: - _inherited.append((_pm_name, _pm_type)) - if _pm_name in _parent_defaults: - Gen.class_member_defaults[ClassName][_pm_name] = _parent_defaults[_pm_name] - if _inherited: - Gen.class_members[ClassName] = _inherited + Gen.class_members[ClassName] - _any_parent_loaded = True + _all_inherited.append((_pm_name, _pm_type)) + if _pm_name in _parent_defaults: + Gen.class_member_defaults[ClassName][_pm_name] = _parent_defaults[_pm_name] + if _all_inherited: + # 防重复注册(2026-08-10):_EmitExternalClassDeclLlvm 可能被多个模块 + # 加载路径重复调用(_LoadModuleDeclarationsFromFile / _LoadDeclarationsFromStubLlvm + # / _TryLoadClassMembersFromPyi 懒加载),此前调用已前置的父类字段会被再次 + # 前置 → class_members 出现重复字段(如 BasicBlock: [Next, Next, Name, ...]) + # → 与 struct elements 数量不匹配 → 属性偏移错乱。按字段名过滤已存在的 + # 父类字段;跨父类重名字段(不同父类各自声明)仍全部保留。 + _cur_member_names_pre: set = {n for n, _ in Gen.class_members.get(ClassName, [])} + _filtered_inherited: list[tuple] = [ + (nm2, tp2) for nm2, tp2 in _all_inherited if nm2 not in _cur_member_names_pre + ] + if _filtered_inherited: + Gen.class_members[ClassName] = _filtered_inherited + Gen.class_members[ClassName] + # 父类字段已处理(可能此前已前置),跳过占位符路径避免叠加 + _any_parent_loaded = True if not _any_parent_loaded and _ParentClasses: # 父类未加载到 class_members(常见于泛型特化基类如 GSListNode[Value], # 其特化不在 .pyi 中)。用 struct body 元素数推断继承字段数。 @@ -1910,7 +1923,53 @@ class ImportHandle(BaseHandle): if _num_elements > _num_members: _num_inherited = _num_elements - _num_members _inherited_ph: list[tuple] = [(f'__inherited_{i}', _st.elements[i]) for i in range(_num_inherited)] + # 占位符路径同样整体前置(继承字段在 struct 头部),与主路径保持一致 Gen.class_members[ClassName] = _inherited_ph + Gen.class_members[ClassName] + # ============================================================ + # 跨模块 vtable 槽布局与定义模块一致:父类方法在前(子类覆盖放父类槽位), + # 子类新增方法在后。定义模块(HandlesClassDef)已按此合并,跨模块若只 + # 注册自身方法(_has_methods_prescan),vtable 槽位会错位 → + # 虚分派调用错误函数(如 MemBuddy.alloc 被解析到槽 13=_fl_find_and_remove + # → 返回 None → "Generator alloc failed")。 + # ============================================================ + if _ParentClasses: + _all_parent_methods: list[str] = [] + _parent_method_names_seen: set[str] = set() + for _pcls in _ParentClasses: + for _pm in list(Gen.class_methods.get(_pcls, [])): + _pm_name: str = _pm.split('.')[-1] if '.' in _pm else _pm + if _pm_name in ('__new__', '__init__', '__before_init__'): + continue + if _pm_name in _parent_method_names_seen: + continue + _parent_method_names_seen.add(_pm_name) + _all_parent_methods.append(_pm) + if _all_parent_methods: + _child_method_map: dict[str, str] = {} + for _m in Gen.class_methods.get(ClassName, []): + _mn: str = _m.split('.')[-1] if '.' in _m else _m + _child_method_map[_mn] = _m + # 从 .vpi 的 FunctionDef 补充子类方法映射(覆盖方法可能尚未注册) + for _item_m in getattr(Node, 'body', []): + if isinstance(_item_m, ast.FunctionDef): + _mn2: str = _item_m.name + if _mn2 in ('__new__', '__init__', '__before_init__'): + continue + _child_method_map[_mn2] = f"{ClassName}.{_mn2}" + _new_methods: list[str] = [] + _covered_names: set[str] = set() + for _pm2 in _all_parent_methods: + _mname2: str = _pm2.split('.')[-1] if '.' in _pm2 else _pm2 + if _mname2 in _child_method_map: + _new_methods.append(_child_method_map[_mname2]) + else: + _new_methods.append(_pm2) + _covered_names.add(_mname2) + for _m3 in list(Gen.class_methods.get(ClassName, [])): + _mn3: str = _m3.split('.')[-1] if '.' in _m3 else _m3 + if _mn3 not in _covered_names: + _new_methods.append(_m3) + Gen.class_methods[ClassName] = _new_methods if has_methods: if IsCVTable: Gen._cross_module_vtable_classes.add(ClassName)