From dc4468593ced10529928c785dd0209c418eaeb6f Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Wed, 14 Oct 2026 22:20:52 +0800 Subject: [PATCH] =?UTF-8?q?fix(viperc):=20CDefine=20=E5=B8=B8=E9=87=8F?= =?UTF-8?q?=E6=8C=89=E4=BD=8D=E5=AE=BD=E5=A4=84=E7=90=86=E6=97=B6=E4=B8=8D?= =?UTF-8?q?=E5=86=8D=E6=8A=8A=E5=8F=AF=E5=AE=B9=E6=AD=A3=E5=80=BC=E7=BF=BB?= =?UTF-8?q?=E8=BD=AC=E6=88=90=E8=B4=9F=E6=95=B0=EF=BC=8C=E4=BF=AE=E5=B8=B8?= =?UTF-8?q?=E9=87=8F=E7=AE=97=E5=BC=8F=E6=8A=98=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 现场:Gargantua _start 的 string.memset(fb, 0, GW * GH * 4)(GW=160, GH=90)应折叠为 57600,实际生成 movl \(= -34560)作为 memset 长度 → 从 0x457ca0 写 4GB → 越界写撞到映射区末尾 0x467000,用户态 #PF err=0x7(cr2 与反汇编逐字对上)。根因:define GW = 160 的位宽按值推断为 8(无符号可容),而 _cdefine_bits_value/_normalize_cdefine_bits 无条件 '(value<<56)>>56' 重解释为有符号 → 160 变 -96(=-96*90*4=-34560)。现只在两种解释都装不下时才截断;位型不变(const_int 本就按位宽截断),仅不再翻转可容正值的语义。 --- App/lib/core/Gen/AssignGenMixin.vp | 28 +++++++++++++++++++--------- App/lib/core/Gen/Expr/ExprGenCdef.vp | 28 +++++++++++++++++++--------- 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/App/lib/core/Gen/AssignGenMixin.vp b/App/lib/core/Gen/AssignGenMixin.vp index 8379e88..05ed170 100644 --- a/App/lib/core/Gen/AssignGenMixin.vp +++ b/App/lib/core/Gen/AssignGenMixin.vp @@ -189,17 +189,27 @@ novirtual class AssignGenMixin: return 0 def _normalize_cdefine_bits(self, value: int64, bits: int) -> int64: - """把值按位宽**截断**后再重解释为该位宽的有符号表示(与 ExprGenCdef._cdefine_bits_value 同口径)。 + """把值按位宽处理:**只有在当前位宽的两种解释下都装不下时才截断**,否则原样保留 + (与 ExprGenCdef._cdefine_bits_value 同口径)。 - 「左侧只会看到截断了的数据」:超宽的值先按 bits 取低位(如 WORD(0x80000000) → 0), - 不是直接把原值搬过来、也不是只对"刚好越界一点"的值做重解释。 - 实现用左移后算术右移,而不是 `value & 0xFFFFFFFF` 这类大掩码字面量: - 掩码字面量(如 4294967295)超出 int32 范围,其加宽方向在 TPC/VPC 上可能判成 sext, - 会得到 0xFFFFFFFFFFFFFFFF 而不是 0xFFFFFFFF,导致截断失效。 + 「左侧只会看到截断了的数据」:超宽的值先按 bits 取低位(如 WORD(0x80000000) → 0)。 + 但**不**把"无符号可容、有符号装不下"的正值重解释成负数:旧实现无条件 + `(value << 56) >> 56`,8 位下的 160 变成 -96,正值静默变负,常量算式随之算错 + (现场:Gargantua `GW * GH * 4` = 57600 被折成 -34560)。 + 实现仍避开大掩码字面量(见下)。 """ - if bits == 8: return (value << 56) >> 56 - if bits == 16: return (value << 48) >> 48 - if bits == 32: return (value << 32) >> 32 + if bits == 8: + if value >= -128 and value <= 127: return value + if value > 127 and (value >> 8) == 0: return value + return (value << 56) >> 56 + if bits == 16: + if value >= -32768 and value <= 32767: return value + if value > 32767 and (value >> 16) == 0: return value + return (value << 48) >> 48 + if bits == 32: + if value >= -2147483647 - 1 and value <= 2147483647: return value + if value > 2147483647 and (value >> 32) == 0: return value + return (value << 32) >> 32 return value def cdefine_decl_bits(self, pool: memhub.MemBuddy*, annot: ast.AST*, value_node: ast.AST*) -> int: diff --git a/App/lib/core/Gen/Expr/ExprGenCdef.vp b/App/lib/core/Gen/Expr/ExprGenCdef.vp index 5dbc2f1..578172a 100644 --- a/App/lib/core/Gen/Expr/ExprGenCdef.vp +++ b/App/lib/core/Gen/Expr/ExprGenCdef.vp @@ -842,17 +842,27 @@ novirtual class ExprGenCdef(ExprGenBase.ExprGenBase): # ============================================================ # cdefine_use_width_value - materialize CDefine constants at the use-site width (TPC-aligned) def _cdefine_bits_value(self, value: int64, bits: int) -> int64: - """把值按位宽**截断**后再重解释为该位宽的有符号表示(与 AssignGenMixin._normalize_cdefine_bits 同口径)。 + """把值按位宽处理:**只有在当前位宽的两种解释下都装不下时才截断**,否则原样保留。 - 「左侧只会看到截断了的数据」:超宽的值先按 bits 取低位(WORD(0x80000000) → 0), - 而不是只对"刚好越界一点"的值做重解释。 - 实现用左移后算术右移,而不是 `value & 0xFFFFFFFF` 这类大掩码字面量: - 掩码字面量(如 4294967295)超出 int32 范围,其加宽方向在 TPC/VPC 上可能判成 sext, - 会得到 0xFFFFFFFFFFFFFFFF 而不是 0xFFFFFFFF,导致截断失效。 + 「左侧只会看到截断了的数据」:超宽的值先按 bits 取低位(如 WORD(0x80000000) → 0)。 + 但不该把"无符号可容、有符号装不下"的**正值**重解释成负数:旧实现无条件 + `(value << 56) >> 56`,8 位下的 160 被读成 -96,正值静默变负 —— 现场 + Gargantua `_start` 的 `string.memset(fb, 0, GW * GH * 4)`(GW=160, GH=90) + 被折成 -34560,作为长度写穿映射区 → #PF。位型不变(const_int 本就按位宽截断), + 只是不再翻转可容正值的语义。实现仍避开大掩码字面量(见下)。 """ - if bits == 8: return (value << 56) >> 56 - if bits == 16: return (value << 48) >> 48 - if bits == 32: return (value << 32) >> 32 + if bits == 8: + if value >= -128 and value <= 127: return value + if value > 127 and (value >> 8) == 0: return value + return (value << 56) >> 56 + if bits == 16: + if value >= -32768 and value <= 32767: return value + if value > 32767 and (value >> 16) == 0: return value + return (value << 48) >> 48 + if bits == 32: + if value >= -2147483647 - 1 and value <= 2147483647: return value + if value > 2147483647 and (value >> 32) == 0: return value + return (value << 32) >> 32 return value def cdefine_use_width_value(self, pool: memhub.MemBuddy*, node: ast.AST*, name: str, value: int64, target_ty: mlirlite.LLVMType*, use_ctx: str = None) -> mlirlite.Value*: