fix(TransPyV): 指针 cast 的跨层 idiom 修正:(str | t.CPtr)(x) → rawptr(x)

c 类(源码违规):(str | t.CPtr)(x) 按既定语义 = i8**(char**,指针的指针),

而这些位置要的是 i8*。TPC 的 return/赋值检查现在按声明精确校验(本次即

TypeGenResolve.vp:1221 `return (str | t.CPtr)(v)` 声明返回 i8* 却 return i8** 被抳下),

该 idiom 在旧的无条件 bitcast 下一直不可见。

改法:86 处 (str | t.CPtr)(X) → rawptr(X)(rawptr 是 t.CPtr 的内置名,同为 i8*;

整数操作数走 inttoptr,指针操作数走 bitcast)。不用 str(X):整数操作数会编译成 itoa

(Gen/FuncGenMixin.vp:1159 注释已记录该陷阱),精确类型仍由使用处的 `: str` 标注承担。

保留 4 处本就该是 i8** 的用例(未改):Converter.vp:820(_g_pyi_cdef_names 声明为

str | t.CPtr 的指针数组)、CallGenCBuiltin.vp:1194/1215(声明即 str | t.CPtr)、

1411(先 cast 再 [0] 取首元素)。

另:Gen/Type/TypeGenResolve.vp:1221 手工改为 return t.CPtr(v)(该文件含你的未提交改动,未一并提交)。
This commit is contained in:
TermiNexus committed 2026-09-28 18:43:59 +08:00
1 parent d579d70113
commit 825fe6d326
19 files changed
+85 -85

No files matched your search

+10 -10
View File
@@ -3744,7 +3744,7 @@ def _repl_stub_find_base(e: rawptr[ReplStubClass], bi: int) -> rawptr[ReplStubCl
StructGen.find_struct_by_module → find_struct 的父类回退口径)"""
if e is None or e.Bases is None or bi < 0 or bi >= e.BaseCount:
return None
pname: str = (str | t.CPtr)(e.Bases[bi])
pname: str = rawptr(e.Bases[bi])
if pname is None:
return None
i: int
@@ -3775,7 +3775,7 @@ def _repl_stub_has_name(arr: sizet*, cnt: int, name: str) -> int:
addr: sizet = arr[i]
if addr == 0:
continue
ex: str = (str | t.CPtr)(addr)
ex: str = rawptr(addr)
if ex is not None and string.strcmp(ex, name) == 0:
return 1
return 0
@@ -3964,7 +3964,7 @@ def _repl_stub_try(e: rawptr[ReplStubClass], mod: llvmlite.LLVMModule*) -> int:
for fi in range(pe.Count):
if cn >= _REPL_STUB_FIELD_MAX:
break
nm: str = (str | t.CPtr)(pe.Names[fi])
nm: str = rawptr(pe.Names[fi])
if nm is None:
continue
if _repl_stub_has_name(e.Names, cn, nm) != 0:
@@ -3976,7 +3976,7 @@ def _repl_stub_try(e: rawptr[ReplStubClass], mod: llvmlite.LLVMModule*) -> int:
for oi in range(e.OwnCount):
if cn >= _REPL_STUB_FIELD_MAX:
break
nm2: str = (str | t.CPtr)(e.OwnNames[oi])
nm2: str = rawptr(e.OwnNames[oi])
if nm2 is None:
continue
if _repl_stub_has_name(e.Names, cn, nm2) != 0:
@@ -4001,7 +4001,7 @@ def _repl_stub_try(e: rawptr[ReplStubClass], mod: llvmlite.LLVMModule*) -> int:
for vi in range(pe.VtCount):
if vn >= _REPL_STUB_VT_MAX:
break
mn: str = (str | t.CPtr)(pe.VtNames[vi])
mn: str = rawptr(pe.VtNames[vi])
if mn is None:
continue
if _repl_stub_has_name(e.VtNames, vn, mn) != 0:
@@ -4012,7 +4012,7 @@ def _repl_stub_try(e: rawptr[ReplStubClass], mod: llvmlite.LLVMModule*) -> int:
for mi in range(e.MethodCount):
if vn >= _REPL_STUB_VT_MAX:
break
mn2: str = (str | t.CPtr)(e.MethodNames[mi])
mn2: str = rawptr(e.MethodNames[mi])
if mn2 is None:
continue
if string.strcmp(mn2, "__init__") == 0:
@@ -4087,7 +4087,7 @@ def _repl_stub_try(e: rawptr[ReplStubClass], mod: llvmlite.LLVMModule*) -> int:
GenApi.add_field(pool, entry, "__vtable__", i8_ptr)
fi3: int
for fi3 in range(cn):
fname: str = (str | t.CPtr)(e.Names[fi3])
fname: str = rawptr(e.Names[fi3])
fty3: llvmlite.LLVMType* = (llvmlite.LLVMType*)(e.Types[fi3])
if fname is None or fty3 is None:
continue
@@ -4104,13 +4104,13 @@ def _repl_stub_try(e: rawptr[ReplStubClass], mod: llvmlite.LLVMModule*) -> int:
string.memset(arr, 0, 8 * e.BaseCount)
bi3: int
for bi3 in range(e.BaseCount):
bnm: str = (str | t.CPtr)(e.Bases[bi3])
bnm: str = rawptr(e.Bases[bi3])
bdup: str = _repl_stub_dupstr(pool, bnm)
if bdup is not None:
arr[bi3] = sizet(bdup)
entry.ParentNames = arr
entry.ParentCount = e.BaseCount
pn: str = (str | t.CPtr)(e.Bases[0])
pn: str = rawptr(e.Bases[0])
entry.ParentName = _repl_stub_dupstr(pool, pn)
if hv == 1 and e.VtTrust == 1 and e.VtCount > 0:
entry.VTableMethods = e.VtNames
@@ -4193,7 +4193,7 @@ def _repl_stub_add_class(pool: memhub.MemBuddy*,
bcnt = _REPL_STUB_FIELD_MAX
bi: int
for bi in range(bcnt):
bnm: str = (str | t.CPtr)(pb[bi])
bnm: str = rawptr(pb[bi])
bdup: str = _repl_stub_dupstr(pool, bnm)
if bdup is not None:
e.Bases[bi] = sizet(bdup)
+4 -4
View File
@@ -1054,7 +1054,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy*, source_dir: str,
# 输出槽防御性初始化(成功路径必全写;未找到/未命中时仅 free 槽本身)
# 槽联合必须用 (sizet*):t.CPtr|t.CPtr 会被折叠成 t.CPtr,
# [0] 变成 1 字节访问 → 指针被截断(0x2e 崩溃根因)。CSizeT 成员为
# 8 字节:写侧 sizet(ptr),读侧必须用 (str | t.CPtr)(slot[0]) 做 u64→
# 8 字节:写侧 sizet(ptr),读侧必须用 rawptr(slot[0]) 做 u64→
# 指针转换;str(slot[0]) 是内置"数字转字符串"(snprintf 到栈缓冲并返回
# 该栈地址),拿到的是十进制文本+栈指针 → free 即 bad-free。
abs_slot: sizet* = (sizet*)(out_abs)
@@ -1072,9 +1072,9 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy*, source_dir: str,
stdlib.free(out_inc)
stdlib.free(mod_buf)
continue
abs_path: str = (str | t.CPtr)(abs_slot[0])
rel_path: str = (str | t.CPtr)(rel_slot[0])
inc_dir: str = (str | t.CPtr)(inc_slot[0])
abs_path: str = rawptr(abs_slot[0])
rel_path: str = rawptr(rel_slot[0])
inc_dir: str = rawptr(inc_slot[0])
# 读文件 + 计算 SHA1(CRLF→LF,与 IncludesScanner 一致)
sha1_r2: str = IncludesScanner.compute_file_sha1(mb, abs_path)