From 43470b6e4ae63dce581405f7efcb9c4700be76cd Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Tue, 18 Aug 2026 08:10:18 +0800 Subject: [PATCH] =?UTF-8?q?fix(vpi):=20=E5=8F=82=E6=95=B0=E6=95=B0?= =?UTF-8?q?=E4=B8=8A=E9=99=90=E5=93=A8=E5=85=B5=20+=20declare=20=E9=93=BE?= =?UTF-8?q?=E9=81=8D=E5=8E=86=E5=93=A8=E5=85=B5=EF=BC=8C=E5=AE=9A=E4=BD=8D?= =?UTF-8?q?=20builtins.vp=20dump=20=E5=8D=A1=E6=AD=BB=E6=A0=B9=E5=9B=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dump 步数哨兵已定位卡死链路为 printf 的 Params 链异常。新增: 1. VpiReader _inject_function_declare/_inject_method_declare 参数数上限 128(fail-fast):vpi tree 深层节点被覆盖损坏时 args_list.__len__() 返回垃圾大数 → add_param 海量次 → Params 链超长,dump 误报成环 2. CallGenBase._ensure_method_declare FuncHead/Params 遍历步数上限 (防 translate 期间死循环) --- App/lib/StubGen/VpiReader.vp | 16 ++++++++++++++++ App/lib/core/Gen/CallGenBase.vp | 11 +++++++++++ 2 files changed, 27 insertions(+) diff --git a/App/lib/StubGen/VpiReader.vp b/App/lib/StubGen/VpiReader.vp index 7eaae33..34620b6 100644 --- a/App/lib/StubGen/VpiReader.vp +++ b/App/lib/StubGen/VpiReader.vp @@ -1139,6 +1139,15 @@ def _inject_function_declare(pool: memhub.MemBuddy | t.CPtr, if args_node.args is not None: args_list: list[ast.AST | t.CPtr] | t.CPtr = args_node.args param_count = args_list.__len__() + # 参数数上限哨兵(fail-fast):vpi tree 深层节点在遍历处理过程中 + # 可能被覆盖损坏(见本文件顶部注释),fd.args 悬空时 __len__() + # 返回垃圾大数 → for 循环 add_param 海量次 → Params 链超长, + # dump 时步数哨兵误报"链表成环"。超限立即报错定位。 + if param_count < 0 or param_count > 128: + stdio.printf( + "[VPIS] 参数数异常: 函数名=%s param_count=%d(fd.args=%llu,tree 可能被覆盖,终止)\n", + fd.name, param_count, t.CUInt64T(fd.args)) + stdlib.exit(1) pi: t.CSizeT for pi in range(param_count): ag: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(args_list.get(pi)) @@ -1257,6 +1266,13 @@ def _inject_method_declare(pool: memhub.MemBuddy | t.CPtr, if args_node.args is not None: args_list: list[ast.AST | t.CPtr] | t.CPtr = args_node.args param_count = args_list.__len__() + # 参数数上限哨兵(fail-fast):与 _inject_function_declare 同因 + # (vpi tree 深层节点被覆盖损坏时 __len__() 返回垃圾大数)。 + if param_count < 0 or param_count > 128: + stdio.printf( + "[VPIS] 参数数异常: 方法名=%s.%s param_count=%d(m_fd.args=%llu,tree 可能被覆盖,终止)\n", + cls_name, m_fd.name, param_count, t.CUInt64T(m_fd.args)) + stdlib.exit(1) pi: t.CSizeT for pi in range(param_count): ag: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(args_list.get(pi)) diff --git a/App/lib/core/Gen/CallGenBase.vp b/App/lib/core/Gen/CallGenBase.vp index 4ce776d..8f3c694 100644 --- a/App/lib/core/Gen/CallGenBase.vp +++ b/App/lib/core/Gen/CallGenBase.vp @@ -504,9 +504,17 @@ class CallGenBase: """ if pool is None or mod is None or call_name is None: return + # 链遍历哨兵(fail-fast):FuncHead/Params 的 Next 被越界写破坏成环时 + # 无上限遍历会死循环(builtins.vp dump 卡死根因排查),超限即报错终止。 + DECLARE_CHAIN_LIMIT: int = 100000 # 检查模块中是否已有同名函数(declare 或 define) existing: llvmlite.Function | t.CPtr = mod.FuncHead + existing_steps: int = 0 while existing is not None: + existing_steps += 1 + if existing_steps > DECLARE_CHAIN_LIMIT: + stdio.printf("[CALLGEN] 链表异常: module funcs(call_name=%s,遍历超限,终止)\n", call_name) + stdlib.exit(1) if existing.Name is not None: if string.strcmp(existing.Name, call_name) == 0: # 已存在:仅当是 declare 且参数数量不足时追加缺失参数 @@ -521,6 +529,9 @@ class CallGenBase: cur_p: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(existing) while cur_p is not None: cur_count += 1 + if cur_count > DECLARE_CHAIN_LIMIT: + stdio.printf("[CALLGEN] 链表异常: func params(call_name=%s,参数链遍历超限,终止)\n", call_name) + stdlib.exit(1) cur_p = cur_p.Next # 只追加缺失的参数(cur_count < param_count 时) if cur_count < param_count: