fix(llvmlite): dump 路径链表遍历加步数上限哨兵,把 IR 成环卡死变确定性报错
builtins.vp 翻译后 dump_ir 卡死(IR 链表 Next 被越界写破坏成环, 遍历无限挂起)。PrintModule/FunctionPrint/RenumberSSA/_scan_type_ for_cross_module_refs 的全部链表遍历(funcs/globals/named types/ params/blocks/lines/struct fields)加 IR_DUMP_CHAIN_LIMIT=100000 步数上限,命中即打印链路名并 exit(1),对齐 memhub.self_check max_steps 的 fail-fast 哲学。
This commit is contained in:
1 parent
15faa1f7b1
commit
f1db31b645
2 files changed
+116
No files matched your search
@@ -4,10 +4,17 @@ import string
|
||||
import viperlib
|
||||
import memhub
|
||||
import stdio
|
||||
import stdlib
|
||||
from linkedlist import GSListNode, GSList
|
||||
from .__types import LLVMType, ParamNode, TypePrint
|
||||
|
||||
|
||||
# dump 哨兵:IR 链表遍历步数上限(成环检测,fail-fast,与 __module.vp 对齐)。
|
||||
# 函数/基本块/指令行链的 Next 被越界写破坏成环时,遍历无限循环挂起;
|
||||
# 超过上限即打印链表名并 exit(1),把"卡死"变成"确定性报错定位"。
|
||||
IR_DUMP_CHAIN_LIMIT: t.CDefine = 100000
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Line: 指令文本行
|
||||
#
|
||||
@@ -425,10 +432,21 @@ def _find_max_ssa_number(func: Function | t.CPtr) -> t.CInt:
|
||||
if func is None or func.Blocks is None:
|
||||
return max_n
|
||||
blk: BasicBlock | t.CPtr = func.Blocks.Head
|
||||
blk_steps: t.CSizeT = 0
|
||||
while blk is not None:
|
||||
blk_steps += 1
|
||||
if blk_steps > IR_DUMP_CHAIN_LIMIT:
|
||||
stdio.printf("[IR-DUMP] 链表成环: func blocks(函数名=%s,ssa 扫描终止)\n", func.Name)
|
||||
stdlib.exit(1)
|
||||
if blk.Lines is not None:
|
||||
line: Line | t.CPtr = blk.Lines.Head
|
||||
line_steps: t.CSizeT = 0
|
||||
while line is not None:
|
||||
line_steps += 1
|
||||
if line_steps > IR_DUMP_CHAIN_LIMIT:
|
||||
stdio.printf("[IR-DUMP] 链表成环: block lines(函数名=%s,块=%s,ssa 扫描终止)\n",
|
||||
func.Name, blk.Name)
|
||||
stdlib.exit(1)
|
||||
if line.Buf is not None:
|
||||
max_n = _scan_max_ssa_in_text(line.Buf, max_n)
|
||||
line = line.Next
|
||||
@@ -550,10 +568,21 @@ def RenumberSSA(func: Function | t.CPtr, pool: memhub.MemBuddy | t.CPtr):
|
||||
# 3. 第二遍扫描:按文本顺序分配新编号
|
||||
next_new: t.CInt = 0
|
||||
blk: BasicBlock | t.CPtr = func.Blocks.Head
|
||||
blk_steps: t.CSizeT = 0
|
||||
while blk is not None:
|
||||
blk_steps += 1
|
||||
if blk_steps > IR_DUMP_CHAIN_LIMIT:
|
||||
stdio.printf("[IR-DUMP] 链表成环: func blocks(函数名=%s,ssa 重编号终止)\n", func.Name)
|
||||
stdlib.exit(1)
|
||||
if blk.Lines is not None:
|
||||
line: Line | t.CPtr = blk.Lines.Head
|
||||
line_steps: t.CSizeT = 0
|
||||
while line is not None:
|
||||
line_steps += 1
|
||||
if line_steps > IR_DUMP_CHAIN_LIMIT:
|
||||
stdio.printf("[IR-DUMP] 链表成环: block lines(函数名=%s,块=%s,ssa 重编号终止)\n",
|
||||
func.Name, blk.Name)
|
||||
stdlib.exit(1)
|
||||
if line.Buf is not None:
|
||||
next_new = _assign_new_numbers(line.Buf, map_arr, max_n, next_new)
|
||||
line = line.Next
|
||||
@@ -573,10 +602,21 @@ def RenumberSSA(func: Function | t.CPtr, pool: memhub.MemBuddy | t.CPtr):
|
||||
|
||||
# 5. 第三遍扫描:替换所有指令行文本
|
||||
blk = func.Blocks.Head
|
||||
blk_steps = 0
|
||||
while blk is not None:
|
||||
blk_steps += 1
|
||||
if blk_steps > IR_DUMP_CHAIN_LIMIT:
|
||||
stdio.printf("[IR-DUMP] 链表成环: func blocks(函数名=%s,ssa 替换终止)\n", func.Name)
|
||||
stdlib.exit(1)
|
||||
if blk.Lines is not None:
|
||||
line: Line | t.CPtr = blk.Lines.Head
|
||||
line_steps = 0
|
||||
while line is not None:
|
||||
line_steps += 1
|
||||
if line_steps > IR_DUMP_CHAIN_LIMIT:
|
||||
stdio.printf("[IR-DUMP] 链表成环: block lines(函数名=%s,块=%s,ssa 替换终止)\n",
|
||||
func.Name, blk.Name)
|
||||
stdlib.exit(1)
|
||||
if line.Buf is not None:
|
||||
new_buf: t.CChar | t.CPtr = _replace_ssa_numbers(
|
||||
line.Buf, pool, map_arr, max_n)
|
||||
@@ -643,7 +683,12 @@ def FunctionPrint(buf: t.CChar | t.CPtr, size: t.CSizeT,
|
||||
if func.Params is not None:
|
||||
cur = func.Params.Head
|
||||
first: t.CInt = 1
|
||||
cur_steps: t.CSizeT = 0
|
||||
while cur is not None:
|
||||
cur_steps += 1
|
||||
if cur_steps > IR_DUMP_CHAIN_LIMIT:
|
||||
stdio.printf("[IR-DUMP] 链表成环: func params(函数名=%s,print 终止)\n", func.Name)
|
||||
stdlib.exit(1)
|
||||
if first == 0:
|
||||
_append_cstr(buf, size, ", ")
|
||||
# 参数属性(如 "noundef"/"nocapture")在类型之前
|
||||
@@ -685,7 +730,12 @@ def FunctionPrint(buf: t.CChar | t.CPtr, size: t.CSizeT,
|
||||
blk: BasicBlock | t.CPtr = None
|
||||
if func.Blocks is not None:
|
||||
blk = func.Blocks.Head
|
||||
blk_steps: t.CSizeT = 0
|
||||
while blk is not None:
|
||||
blk_steps += 1
|
||||
if blk_steps > IR_DUMP_CHAIN_LIMIT:
|
||||
stdio.printf("[IR-DUMP] 链表成环: func blocks(函数名=%s,print 终止)\n", func.Name)
|
||||
stdlib.exit(1)
|
||||
# 块标签
|
||||
if blk.Name is not None:
|
||||
_append_cstr(buf, size, blk.Name)
|
||||
@@ -695,7 +745,13 @@ def FunctionPrint(buf: t.CChar | t.CPtr, size: t.CSizeT,
|
||||
if blk.Lines is not None:
|
||||
line = blk.Lines.Head
|
||||
has_lines: t.CInt = 0
|
||||
line_steps: t.CSizeT = 0
|
||||
while line is not None:
|
||||
line_steps += 1
|
||||
if line_steps > IR_DUMP_CHAIN_LIMIT:
|
||||
stdio.printf("[IR-DUMP] 链表成环: block lines(函数名=%s,块=%s,print 终止)\n",
|
||||
func.Name, blk.Name)
|
||||
stdlib.exit(1)
|
||||
if line.Buf is not None:
|
||||
_append_cstr(buf, size, " ")
|
||||
_append_cstr(buf, size, line.Buf)
|
||||
|
||||
@@ -227,12 +227,24 @@ class LLVMModule:
|
||||
# 确保 stub.ll 包含被 declare/define 引用的跨模块类型定义
|
||||
# 修复:alloc_buf 返回 viperio.Buf,但 Buf 类型未在 NamedTypeHead 中注册
|
||||
func_scan: Function | t.CPtr = self.FuncHead
|
||||
func_scan_steps: t.CSizeT = 0
|
||||
while func_scan is not None:
|
||||
func_scan_steps += 1
|
||||
if func_scan_steps > IR_DUMP_CHAIN_LIMIT:
|
||||
stdio.printf("[IR-DUMP] 链表成环: module funcs(FuncCount=%zu,dump 终止)\n",
|
||||
self.FuncCount)
|
||||
stdlib.exit(1)
|
||||
if func_scan.RetTy is not None:
|
||||
self.ensure_opaque_for_type(pool, func_scan.RetTy)
|
||||
if func_scan.Params is not None:
|
||||
param_scan: Param | t.CPtr = func_scan.Params.Head
|
||||
param_scan_steps: t.CSizeT = 0
|
||||
while param_scan is not None:
|
||||
param_scan_steps += 1
|
||||
if param_scan_steps > IR_DUMP_CHAIN_LIMIT:
|
||||
stdio.printf("[IR-DUMP] 链表成环: func params(函数名=%s,dump 终止)\n",
|
||||
func_scan.Name)
|
||||
stdlib.exit(1)
|
||||
if param_scan.Ty is not None:
|
||||
self.ensure_opaque_for_type(pool, param_scan.Ty)
|
||||
param_scan = param_scan.Next
|
||||
@@ -241,7 +253,13 @@ class LLVMModule:
|
||||
# 结构体定义缓冲区:48 字段 × ~50 字节/字段类型名 ≈ 2400 字节,4096 足够
|
||||
# 在循环外分配一次并复用,减少 pool 碎片
|
||||
ty_buf: t.CChar | t.CPtr = pool.alloc(4096)
|
||||
nt_steps: t.CSizeT = 0
|
||||
while nt is not None:
|
||||
nt_steps += 1
|
||||
if nt_steps > IR_DUMP_CHAIN_LIMIT:
|
||||
stdio.printf("[IR-DUMP] 链表成环: module named types(NamedTypeCount=%zu,dump 终止)\n",
|
||||
self.NamedTypeCount)
|
||||
stdlib.exit(1)
|
||||
if nt.Ty is not None:
|
||||
if ty_buf is not None:
|
||||
ty_buf[0] = '\0'
|
||||
@@ -255,9 +273,15 @@ class LLVMModule:
|
||||
|
||||
# 全局变量
|
||||
gv: GlobalVariable | t.CPtr = self.GlobalHead
|
||||
gv_steps: t.CSizeT = 0
|
||||
if mode == OUTPUT_STUB:
|
||||
# stub 模式:输出 external global(无初值)
|
||||
while gv is not None:
|
||||
gv_steps += 1
|
||||
if gv_steps > IR_DUMP_CHAIN_LIMIT:
|
||||
stdio.printf("[IR-DUMP] 链表成环: module globals stub(GlobalCount=%zu,dump 终止)\n",
|
||||
self.GlobalCount)
|
||||
stdlib.exit(1)
|
||||
_print_global_stub(buf, size, gv, pool)
|
||||
_append_cstr(buf, size, "\n")
|
||||
gv = gv.Next
|
||||
@@ -266,6 +290,11 @@ class LLVMModule:
|
||||
# text 模式跳过无初值的全局变量(纯声明)
|
||||
gv_idx: t.CInt = 0
|
||||
while gv is not None:
|
||||
gv_steps += 1
|
||||
if gv_steps > IR_DUMP_CHAIN_LIMIT:
|
||||
stdio.printf("[IR-DUMP] 链表成环: module globals(GlobalCount=%zu,dump 终止)\n",
|
||||
self.GlobalCount)
|
||||
stdlib.exit(1)
|
||||
if mode == OUTPUT_TEXT and gv.Initializer is None:
|
||||
gv = gv.Next
|
||||
gv_idx += 1
|
||||
@@ -281,7 +310,13 @@ class LLVMModule:
|
||||
# text 模式下如果输出了全局变量,也加空行
|
||||
had_global: t.CInt = 0
|
||||
gv2: GlobalVariable | t.CPtr = self.GlobalHead
|
||||
gv2_steps: t.CSizeT = 0
|
||||
while gv2 is not None:
|
||||
gv2_steps += 1
|
||||
if gv2_steps > IR_DUMP_CHAIN_LIMIT:
|
||||
stdio.printf("[IR-DUMP] 链表成环: module globals text(GlobalCount=%zu,dump 终止)\n",
|
||||
self.GlobalCount)
|
||||
stdlib.exit(1)
|
||||
if gv2.Initializer is not None:
|
||||
had_global = 1
|
||||
break
|
||||
@@ -292,7 +327,13 @@ class LLVMModule:
|
||||
# 遍历函数
|
||||
func: Function | t.CPtr = self.FuncHead
|
||||
func_idx: t.CInt = 0
|
||||
func_steps: t.CSizeT = 0
|
||||
while func is not None:
|
||||
func_steps += 1
|
||||
if func_steps > IR_DUMP_CHAIN_LIMIT:
|
||||
stdio.printf("[IR-DUMP] 链表成环: module funcs print(FuncCount=%zu,dump 终止)\n",
|
||||
self.FuncCount)
|
||||
stdlib.exit(1)
|
||||
if mode == OUTPUT_STUB:
|
||||
# stub 模式:仅输出 declare(IsDeclared==1)
|
||||
if func.IsDeclared == 1:
|
||||
@@ -461,7 +502,13 @@ def _scan_type_for_cross_module_refs(pool: memhub.MemBuddy | t.CPtr,
|
||||
# 例如 TypeRegistry{HashTable*, MemManager*} 中的 HashTable 引用
|
||||
if sfields is not None:
|
||||
fld: ParamNode | t.CPtr = sfields
|
||||
fld_steps: t.CSizeT = 0
|
||||
while fld is not None:
|
||||
fld_steps += 1
|
||||
if fld_steps > IR_DUMP_CHAIN_LIMIT:
|
||||
stdio.printf("[IR-DUMP] 链表成环: struct fields(sname=%s,dump 终止)\n",
|
||||
sname)
|
||||
stdlib.exit(1)
|
||||
if fld.Ty is not None:
|
||||
_scan_type_for_cross_module_refs(pool, mod, fld.Ty, depth + 1)
|
||||
fld = fld.Next
|
||||
@@ -471,7 +518,13 @@ def _scan_type_for_cross_module_refs(pool: memhub.MemBuddy | t.CPtr,
|
||||
# 顶层结构体(非指针):递归扫描字段
|
||||
if sfields2 is not None:
|
||||
fld2: ParamNode | t.CPtr = sfields2
|
||||
fld2_steps: t.CSizeT = 0
|
||||
while fld2 is not None:
|
||||
fld2_steps += 1
|
||||
if fld2_steps > IR_DUMP_CHAIN_LIMIT:
|
||||
stdio.printf("[IR-DUMP] 链表成环: struct fields2(sname=%s,dump 终止)\n",
|
||||
sname2)
|
||||
stdlib.exit(1)
|
||||
if fld2.Ty is not None:
|
||||
_scan_type_for_cross_module_refs(pool, mod, fld2.Ty, depth + 1)
|
||||
fld2 = fld2.Next
|
||||
@@ -522,6 +575,13 @@ OUTPUT_FULL: t.CDefine = 0 # 完整 IR(stub + text)
|
||||
OUTPUT_STUB: t.CDefine = 1 # 仅声明(header + 类型定义 + declare + external global)
|
||||
OUTPUT_TEXT: t.CDefine = 2 # 仅代码(define + global 带初值)
|
||||
|
||||
# dump 哨兵:IR 链表遍历步数上限(成环检测,fail-fast)。
|
||||
# 任何一条链(函数/全局/命名类型/结构体字段)的 Next 被越界写破坏成环时,
|
||||
# 遍历会无限循环导致 tpv.exe 挂起(builtins.vp dump 卡死根因排查)。
|
||||
# 超过上限即打印链表名并 exit(1),把"卡死"变成"确定性报错定位"
|
||||
# (对齐 memhub.self_check 的 max_steps 哲学)。
|
||||
IR_DUMP_CHAIN_LIMIT: t.CDefine = 100000
|
||||
|
||||
|
||||
# ============================================================
|
||||
# LLVMModulePrint: 将模块序列化为 .ll 文本
|
||||
|
||||
Reference in new issue
Block a user