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:
TermiNexus committed 2026-08-18 07:59:39 +08:00
1 parent 15faa1f7b1
commit f1db31b645
2 files changed
+116

No files matched your search

+56
View File
@@ -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)
+60
View File
@@ -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 文本