Skip to content

Commit a2e354b

Browse files
Lef IoannidisCopilot
andcommitted
Fix UInt8/UInt16 comparison after wrapping arithmetic (#694)
Comparisons (Eq, Neq, Lt, Lte, Gt, Gte) on UInt8/UInt16 after wrapping arithmetic (add_mod, sub_mod, mul_mod, shift_left, xor, or, etc.) produced wrong C code. The uint32 intermediate from mk_arith was compared directly without masking back to the original width. For example, (255uy +%^ 1uy) = 0uy generated: (uint32_t)255 + (uint32_t)1 == 0 => 256 == 0 => false (WRONG) Fix: handle comparisons in mk_expr (not mk_arith) with a dedicated pattern that only widens+masks operands containing arithmetic subexpressions. Atomic operands (variables, field accesses, etc.) are compared at their native width without unnecessary casts. Now generates: simple: a == b (no casts) arith: ((uint32_t)a + (uint32_t)b & 0xFFU) == c (only arith side) Fixes #694. Also fixes #689, #691, #692, #693 (same root cause). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent d859556 commit a2e354b

File tree

1 file changed

+20
-4
lines changed

1 file changed

+20
-4
lines changed

lib/AstToCStar.ml

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -311,8 +311,7 @@ and mask w e =
311311
and is_integer_arith op w =
312312
w <> K.Bool && not (Constant.is_float w) && K.is_unsigned w && match op with
313313
| K.Add | AddW | Sub | SubW | Div | DivW | Mult | MultW | Mod
314-
| BOr | BAnd | BXor | BShiftL | BShiftR | BNot
315-
| Eq | Neq | Lt | Lte | Gt | Gte ->
314+
| BOr | BAnd | BXor | BShiftL | BShiftR | BNot ->
316315
true
317316
| _ ->
318317
false
@@ -343,8 +342,6 @@ and mk_arith env e =
343342
CStar.Call (Op op, [ mask_if a1 w e1; mask_if a2 w e2 ])
344343
| BShiftR ->
345344
CStar.Call (Op op, [ mask_if a1 w e1; e2 ])
346-
| Eq | Neq | Lt | Lte | Gt | Gte ->
347-
CStar.Call (Op op, [ mask_if a1 w e1; mask_if a2 w e2 ])
348345
| _ ->
349346
assert false
350347
end, false, w1 || w2
@@ -417,6 +414,25 @@ and mk_expr env in_stmt under_initializer_list e =
417414
else
418415
e'
419416

417+
| EApp ({ node = EOp (op, w); _ }, [ e1; e2 ])
418+
when Constant.is_comp_op op
419+
&& w <> K.Bool && not (Constant.is_float w) && K.is_unsigned w ->
420+
(* Comparisons on narrow unsigned types: only widen+mask operands that
421+
contain arithmetic. Atomic operands (variables, field accesses, etc.)
422+
are compared at their native width without unnecessary casts. *)
423+
let needs_arith e = match e.node with
424+
| EApp ({ node = EOp (op, w); _ }, _) -> is_integer_arith op w
425+
| _ -> false
426+
in
427+
let mk_cmp_operand e =
428+
if needs_arith e then
429+
let e', a, _ = mk_arith env e in
430+
if a then e' else mask w e'
431+
else
432+
mk_expr env false e
433+
in
434+
CStar.Call (Op op, [ mk_cmp_operand e1; mk_cmp_operand e2 ])
435+
420436
| EApp (e, es) ->
421437
(* Functions that only take a unit take no argument. *)
422438
let t, _ = flatten_arrow e.typ in

0 commit comments

Comments
 (0)