From 093ff5f66d48277fa7308958181c2a53df5ece92 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Fri, 25 Sep 2026 13:15:04 +0800 Subject: [PATCH] =?UTF-8?q?fix(viperlib):=20=E6=B5=AE=E7=82=B9=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E5=8C=96=E7=9A=84=20inf/nan=20=E4=BF=9D=E6=8A=A4?= =?UTF-8?q?=E5=A4=B1=E6=95=88=E5=AF=BC=E8=87=B4=20%g=20=E6=AD=BB=E5=BE=AA?= =?UTF-8?q?=E7=8E=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根因: _check_special_float 的位双关 (把 double 位模式读成 uint64) 被 TPC 前端静默丢弃——IR 里 fbits 恒为 0 (store i64 0 后直接 load,没有把 fv 写进 fbits),函数恒返回 0,于是 %f/%e/%g/%a 的 inf/nan 保护全部失效。 后果: inf 落入 %g 的指数归一化循环 while fv>=10.0 (inf/10==inf 恒真) → 死循环,实测卡死在 vsnprintf:974(Ctrl+C 栈转储权威帧 #0)。 修复: _check_special_float 改为纯浮点语义判定 (fv!=fv 判 NaN;fv-fv!=fv-fv 判 +-inf);另给 4 处对 inf 不收敛的循环各加迭代上界 400 (正常最多约 308 次) 作纵深防御。 注: 位双关语句被静默丢弃属 TPC 前端缺陷,需另立项;va_arg(ap, double) 经生成 IR 核对是正确的 (va_arg 内建读 XMM 保存区且 gp/fp 各自推进),非本次原因。 --- viperlib.vp | 52 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/viperlib.vp b/viperlib.vp index 4a8d1e3..36b7a9c 100644 --- a/viperlib.vp +++ b/viperlib.vp @@ -28,17 +28,23 @@ export def snprintf(buf: str, size: sizet, fmt: str, *args) -> int: ret: int = vsnprintf(buf, size, fmt, args) return ret -# Check floating-point special values (IEEE 754) -# Return: 0=normal, 1=+inf, 2=-inf, 3=nan +# 检查浮点特殊值(IEEE 754) +# 返回:0=正常, 1=+inf, 2=-inf, 3=nan +# 注意:不可用位双关 `*&fbits = *&fv` 读取 IEEE 位模式——该赋值会被编译器静默 +# 丢弃(IR 中 fbits 恒为 0,见 TransPyV/output/db514c1af999c5f5.text.ll),会使 +# 本函数恒返回 0、特殊值检查彻底失效,进而让 inf 进入浮点格式化循环而死循环。 +# 这里改用纯浮点语义判定,不依赖任何位操作: +# NaN :fv != fv 为真 +# ±inf:fv - fv 得到 NaN(有限值得到 0.0) def _check_special_float(fv: double) -> int: - fbits: uint64 = 0 - *&fbits = *&fv - if ((fbits >> 52) & 0x7FF) != 0x7FF: return 0 - is_neg: int = 1 if (fbits >> 63) != 0 else 0 - if (fbits & 0x000FFFFFFFFFFFFF) == 0: - if is_neg: return 2 + if fv != fv: + return 3 + diff: double = fv - fv + if diff != diff: + if fv < 0.0: + return 2 return 1 - return 3 + return 0 export def vsnprintf(buf: bytes, size: sizet, fmt: str, ap: str) -> int: if fmt is None: return 0 @@ -626,8 +632,11 @@ export def vsnprintf(buf: bytes, size: sizet, fmt: str, ap: str) -> int: di = 1 else: scale: double = 1.0 - while work >= scale * 10.0: + # 上界防护:inf 会让 `work >= scale*10.0` 永真,正常有限值最多 308 次 + scale_guard: int = 0 + while work >= scale * 10.0 and scale_guard < 400: scale *= 10.0 + scale_guard += 1 while scale >= 1.0 and di < TEMP_BUF_SIZE - 1: d: int = int(work / scale) if d > 9: d = 9 @@ -779,12 +788,17 @@ export def vsnprintf(buf: bytes, size: sizet, fmt: str, ap: str) -> int: ptr += _step exp10: int = 0 if fv != 0.0: - while fv >= 10.0: + # 上界防护:inf 会让下面两个循环永真(inf/10==inf、inf*10==inf) + exp_guard: int = 0 + while fv >= 10.0 and exp_guard < 400: fv /= 10.0 exp10 += 1 - while fv < 1.0: + exp_guard += 1 + exp_guard = 0 + while fv < 1.0 and exp_guard < 400: fv *= 10.0 exp10 -= 1 + exp_guard += 1 int_digit: int = int(fv) if int_digit > 9: int_digit = 9 if int_digit < 0: int_digit = 0 @@ -971,12 +985,17 @@ export def vsnprintf(buf: bytes, size: sizet, fmt: str, ap: str) -> int: fv_orig: double = fv exp10: int = 0 if fv != 0.0: - while fv >= 10.0: + # 上界防护:卡死现场即此循环(inf 会让 fv>=10.0 永真,inf/10==inf) + exp_guard: int = 0 + while fv >= 10.0 and exp_guard < 400: fv /= 10.0 exp10 += 1 - while fv < 1.0: + exp_guard += 1 + exp_guard = 0 + while fv < 1.0 and exp_guard < 400: fv *= 10.0 exp10 -= 1 + exp_guard += 1 g_use_e: int = 0 if exp10 < -4 or exp10 >= precision: g_use_e = 1 @@ -1029,8 +1048,11 @@ export def vsnprintf(buf: bytes, size: sizet, fmt: str, ap: str) -> int: g_len = 1 else: scale: double = 1.0 - while work >= scale * 10.0: + # 上界防护:inf 会让 `work >= scale*10.0` 永真,正常有限值最多 308 次 + scale_guard: int = 0 + while work >= scale * 10.0 and scale_guard < 400: scale *= 10.0 + scale_guard += 1 while scale >= 1.0 and g_len < TEMP_BUF_SIZE - 1: d: int = int(work / scale) if d > 9: d = 9