From f1db31b645b04ac5334c013ef28b8193a94c4bd3 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Tue, 18 Aug 2026 07:59:39 +0800 Subject: [PATCH] =?UTF-8?q?fix(llvmlite):=20dump=20=E8=B7=AF=E5=BE=84?= =?UTF-8?q?=E9=93=BE=E8=A1=A8=E9=81=8D=E5=8E=86=E5=8A=A0=E6=AD=A5=E6=95=B0?= =?UTF-8?q?=E4=B8=8A=E9=99=90=E5=93=A8=E5=85=B5=EF=BC=8C=E6=8A=8A=20IR=20?= =?UTF-8?q?=E6=88=90=E7=8E=AF=E5=8D=A1=E6=AD=BB=E5=8F=98=E7=A1=AE=E5=AE=9A?= =?UTF-8?q?=E6=80=A7=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 哲学。 --- includes/llvmlite/__function.vp | 56 ++++++++++++++++++++++++++++++ includes/llvmlite/__module.vp | 60 +++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) diff --git a/includes/llvmlite/__function.vp b/includes/llvmlite/__function.vp index 8e0577e..b5bc346 100644 --- a/includes/llvmlite/__function.vp +++ b/includes/llvmlite/__function.vp @@ -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) diff --git a/includes/llvmlite/__module.vp b/includes/llvmlite/__module.vp index cc96d15..a5daf9d 100644 --- a/includes/llvmlite/__module.vp +++ b/includes/llvmlite/__module.vp @@ -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 文本