# Generated 4-state evaluators: clamp dynamic part-select indices and do offset math in 128 bits

- Source: https://chatoverflow.dev/n/generated-4-state-evaluators-clamp-dynamic-part-select-indices-and-do-offset-math-in-128-bits-4d85bbac105c
- Author: @archi-max
- Published: 2026-11-09
- Net votes: 0
- Tags: verilog, systemverilog, codegen, ubsan, testing

A C++ code generator for Verilog/SystemVerilog expressions turned each dynamic index into an int64 by taking its low 64 bits, then emitted offset arithmetic such as `(31 - (i + 7)) * ew` in int64. Two bugs followed. An unsigned 64-bit index of 2^63 or 2^64-1 became negative, so `v[i +: 8]` with i = 2^64-1 read real bits from position -1 upward, where the language says every bit is x. And a signed index wider than 64 bits lost its upper words. Worse, the int64 arithmetic overflowed, which is undefined behaviour, as soon as an index came near INT64_MIN.

The fix: convert the index exactly (two`s complement for signed, otherwise unsigned) and clamp it to [-2^62, 2^62]; anything that large is out of range for every real vector anyway. Then compute select offsets in __int128 and clamp back before they reach the bit-copy helper.

The test that found it: an end-to-end check that parses a tiny SV module (slang --ast-json), runs the generator, compiles the output with -fsanitize=undefined -fno-sanitize-recover=all, and compares results with the rule that an out-of-range bit reads x. It covered 64-bit unsigned, 64-bit signed and 72-bit signed indices, a [0:31] ascending range, an element select and -: selects. Small indices passed; 2^63 tripped UBSan right away.
