Skip to content

fix(timer): make the wrap-around top-bit test shift unsigned (1U << 31) - #97

Open
randomizedcoder wants to merge 1 commit into
PlatformLab:mainfrom
randomizedcoder:fix/timer-signed-shift
Open

randomizedcoder wants to merge 1 commit into
PlatformLab:mainfrom
randomizedcoder:fix/timer-signed-shift

Conversation

@randomizedcoder

Copy link
Copy Markdown

Bug: undefined 1 << 31 in the NEED_ACK wrap-around test

homa_timer_check_rpc() uses a wrap-around-safe comparison to decide when to send a NEED_ACK, testing the top bit of an unsigned tick difference:

if ((rpc->done_timer_ticks + homa->request_ack_ticks
        - 1 - homa->timer_ticks) & 1 << 31) {

1 << 31 shifts a 1 into the sign bit of a signed int — the result (2³¹) isn't representable in int, which is undefined behavior in C.

Because 1 << 31 is a constant expression, the compiler folds it at compile time, so the runtime behavior is correct on gcc/x86 today (and UBSan's runtime shift check never sees it). It remains UB on paper and a portability trap, and -Wshift-overflow=2 flags it.

Fix

-					- 1 - homa->timer_ticks) & 1 << 31) {
+					- 1 - homa->timer_ticks) & 1U << 31) {

1U << 31 is well-defined unsigned. The operands are already unsigned (done_timer_ticks/timer_ticks are u32, so the whole expression is unsigned int), so the masked value — the top bit of the wrap difference — is identical.

Verification (compiler gate + regression)

Before:  ../homa_timer.c:37: warning: result of '1 << 31' requires 33 bits to
         represent, but 'int' only has 32 bits [-Wshift-overflow=]
After:   (clean — no homa_timer.c warning)

-Wshift-overflow=2. The timer unit suite stays green (10/10); homa_timer_check_rpc__request_ack still walks its tick sequence to "xmit NEED_ACK", confirming the behavior is unchanged.

Note on the gate: the initial plan expected UBSan to catch this, but a constant-folded shift produces no runtime shift for UBSan to instrument — so the authoritative gate here is the compiler's -Wshift-overflow=2, backed by the unchanged behavioral test.

homa_timer_check_rpc() decides whether to send NEED_ACK with a
wrap-around-safe comparison that tests the top bit of an unsigned
difference:

    (rpc->done_timer_ticks + homa->request_ack_ticks
        - 1 - homa->timer_ticks) & 1 << 31

`1 << 31` shifts a 1 into the sign bit of a signed int, which is
undefined behavior in C (the result isn't representable in int). Because
it's a constant expression the compiler folds it, so behavior happens to
be correct on gcc/x86 today, but it's UB on paper and a portability trap;
`-Wshift-overflow=2` flags it. Use `1U << 31` so the shift is well-defined
unsigned; the surrounding operands are already unsigned (u32 dominates the
expression), so the masked result is unchanged.

Verified: `-Wshift-overflow=2` warns at homa_timer.c:37 before and is
clean after; the timer unit suite stays green (10/10), including
homa_timer_check_rpc__request_ack whose tick sequence still emits
"xmit NEED_ACK".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant