fix(tpv): 去掉条目指针数组往返,改上界/量长直写(修自举 ASan strcat -1 崩溃)
This commit is contained in:
1 parent
82eea2719f
commit
471bedbcf4
2 files changed
+45
-36
No files matched your search
@@ -388,9 +388,10 @@ class TypeGenErr(TypeGenBase.TypeGenBase):
|
||||
[D5·截断纪律] 旧实现按 `an * 32 + 1` 预估缓冲,再用 `_strappend` 以
|
||||
`remain - 1` 截断且**不报错**:参数名偏长(或参数偏多)时编码串被静默
|
||||
截断 ⇒ `infer_expr_type` 的 `strstr(param_types, "name:")` 查找失配 /
|
||||
命中他人前缀 ⇒ 静默回落 Int32(类型误判)。现改为**两遍精确分配**:
|
||||
先逐参数生成条目(指针暂存数组)并累计长度,再按精确长度分配后拼接——
|
||||
不存在长度上限,故无需截断;`_strappend` 一并删除(唯一调用点在本函数)。
|
||||
命中他人前缀 ⇒ 静默回落 Int32(类型误判)。现改为**上界预估 + 单遍就地
|
||||
拼接**:段一是只扫参数名的上界(name + ':' + 位宽 + ',' + NUL),段二是
|
||||
解析类型后逐条目就地格式化并立即拼接 —— 缓冲恒够,不存在截断;
|
||||
`_strappend` 一并删除(唯一调用点在本函数)。
|
||||
"""
|
||||
if args_node is None:
|
||||
return None
|
||||
@@ -402,11 +403,25 @@ class TypeGenErr(TypeGenBase.TypeGenBase):
|
||||
if an == 0:
|
||||
return None
|
||||
|
||||
# 1) 逐参数生成条目 "name:bits"(精确分配),指针暂存
|
||||
ents: sizet | t.CPtr = pool.alloc(an * 8)
|
||||
if ents is None:
|
||||
# 1) 上界估长(**只扫参数名**,不解析类型也不需要暂存结果指针):
|
||||
# 每条 = name + ':' + 位宽(int32 十进制最长 11 字符含符号)+ ',';再加 NUL。
|
||||
# ⚠ 这里必须"上界"而非"精确":此前版本把每条目指针存进 sizet 数组、
|
||||
# 再取出转回指针 strcat,自举出的二进制上取回了 -1(0xffffffffffffffff)
|
||||
# ⇒ ASan: access-violation in strcat(build_param_types_str)。
|
||||
# 改为上界缓冲后**不需要数组往返**,每条目就地格式化、立即拼接。
|
||||
bound: sizet = 1 # 末尾 NUL
|
||||
pre_i: sizet
|
||||
for pre_i in range(an):
|
||||
pre_arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(pre_i))
|
||||
if pre_arg is None or pre_arg.arg is None:
|
||||
continue
|
||||
bound += string.strlen(pre_arg.arg) + 1 + 12 + 1
|
||||
buf: str = pool.alloc(bound)
|
||||
if buf is None:
|
||||
return None
|
||||
total: sizet = 1 # 末尾 NUL
|
||||
buf[0] = '\0'
|
||||
|
||||
# 2) 单遍:解析类型 → 就地格式化条目 → 立即拼接(缓冲为上界,不会截断)
|
||||
cnt: sizet = 0
|
||||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
for ai in range(an):
|
||||
@@ -427,28 +442,17 @@ class TypeGenErr(TypeGenBase.TypeGenBase):
|
||||
if bits == 0:
|
||||
bits = 32
|
||||
nlen: sizet = string.strlen(arg.arg)
|
||||
# name + ':' + 十进制位宽(int32 最长 11 字符)+ NUL
|
||||
ent: str = pool.alloc(nlen + 1 + 12 + 1)
|
||||
# 条目缓冲:name + ':' + 位宽(预留 16 字节,足够 %d 任意取值)+ NUL
|
||||
ent: str = pool.alloc(nlen + 1 + 16 + 1)
|
||||
if ent is None:
|
||||
continue
|
||||
string.strcpy(ent, arg.arg)
|
||||
ent[nlen] = ':'
|
||||
viperlib.snprintf(ent + nlen + 1, 12, "%d", bits)
|
||||
ents[cnt] = sizet(ent)
|
||||
viperlib.snprintf(ent + nlen + 1, 16, "%d", bits)
|
||||
if cnt > 0:
|
||||
string.strcat(buf, ",")
|
||||
string.strcat(buf, ent)
|
||||
cnt += 1
|
||||
total += nlen + 1 + string.strlen(ent + nlen + 1)
|
||||
if cnt == 0:
|
||||
return None
|
||||
if cnt > 1:
|
||||
total += cnt - 1 # 分隔符 ","
|
||||
|
||||
# 2) 按精确长度分配 + 拼接(不会截断)
|
||||
buf: str = pool.alloc(total)
|
||||
if buf is None:
|
||||
return None
|
||||
buf[0] = '\0'
|
||||
for i2 in range(cnt):
|
||||
if i2 > 0:
|
||||
string.strcat(buf, ",")
|
||||
string.strcat(buf, (str | t.CPtr)(t.CVoid(ents[i2], t.CPtr)))
|
||||
return buf
|
||||
@@ -163,13 +163,11 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
if elts is None or pool is None:
|
||||
return None
|
||||
n3: sizet = len(elts)
|
||||
# 1) 解析全部元素(结果指针暂存,避免二次解析)
|
||||
es_arr: sizet | t.CPtr = None
|
||||
if n3 > 0:
|
||||
es_arr = pool.alloc(n3 * 8)
|
||||
if es_arr is None:
|
||||
return None
|
||||
total3: sizet = 2 # open + close
|
||||
# 1) 量长(解析结果用完即弃):**不把元素指针暂存进数组再取回**——
|
||||
# 该「sizet 数组往返再转回指针」的写法在自举出的二进制上会取回 -1
|
||||
# (0xffffffffffffffff)⇒ ASan access-violation in strcat(同类现场见
|
||||
# TypeGenErr.build_param_types_str)。此处改为二次解析 + 直写。
|
||||
total3: sizet = 2 # open + close(各按 1 字节算;实参为空串时多算无害)
|
||||
cnt3: sizet = 0
|
||||
for i3 in range(n3):
|
||||
e3: ast.AST | t.CPtr = elts.get(i3)
|
||||
@@ -181,21 +179,28 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
e3, "类型注解的元素无法解析为类型名(列表/元组注解)", "NameError")
|
||||
return None
|
||||
es_arr[cnt3] = sizet(es3)
|
||||
cnt3 += 1
|
||||
total3 += string.strlen(es3)
|
||||
if cnt3 > 1:
|
||||
total3 += (cnt3 - 1) * 2 # 分隔符 ", "
|
||||
# 2) 按精确长度分配 + 拼接(无上限,不会截断)
|
||||
# 2) 按精确长度分配 + 二次解析直写(无上限,不会截断)
|
||||
buf4: str = pool.alloc(total3 + 1)
|
||||
if buf4 is None:
|
||||
return None
|
||||
buf4[0] = '\0'
|
||||
string.strcat(buf4, open_ch)
|
||||
for i4 in range(cnt3):
|
||||
if i4 > 0:
|
||||
wrote3: sizet = 0
|
||||
for i4 in range(n3):
|
||||
e4: ast.AST | t.CPtr = elts.get(i4)
|
||||
if e4 is None:
|
||||
continue
|
||||
es4: str = self._subscript_slice_to_str(pool, e4)
|
||||
if es4 is None:
|
||||
continue # 第一遍已校验过,此处不会发生
|
||||
if wrote3 > 0:
|
||||
string.strcat(buf4, ", ")
|
||||
string.strcat(buf4, (str | t.CPtr)(t.CVoid(es_arr[i4], t.CPtr)))
|
||||
string.strcat(buf4, es4)
|
||||
wrote3 += 1
|
||||
string.strcat(buf4, close_ch)
|
||||
return buf4
|
||||
def _is_sha1_prefixed(self, s: str) -> int:
|
||||
|
||||
Reference in new issue
Block a user