Skip to content

[issues-find] [S3] Random32 updates RNG with interrupts enabled (src/random.c) #278

Description

@evilchinesefood

[issues-find] filed on 2026-09-02, lens Concurrency, at commit 545f501.

Severity: S3 (minor)

What is wrong
Random32 load-modify-stores gRngValue with interrupts enabled. VBlankIntr in src/main.c calls AdvanceRandom (line 383), which calls Random32 whenever sRngLoopUnlocked is TRUE; that lock is only taken around LOOP_RANDOM macros, not around Random32 itself.

Where
src/random.c:45 in Random32

u32 NAKED Random32(void)
{
    asm(".thumb\n\
    push {r4, r5, r6}\n\
    mov r6, #11\n\
    ldr r5, =gRngValue\n\
    ldmia r5!, {r1, r2, r3, r4}\n\
    @ result = a + b + (d+=STREAM1)\n\
    add r1, r1, r2\n\
    add r0, r1, r4\n\
    add r4, r4, #" STR(STREAM1) "\n\

Why it matters
A VBlank nested inside Random32 tears gRngValue, so later Random/Random32 results are wrong (and can desync non-link systems that consume the same stream).

How to observe it
Static finding; not executed.

Recommended fix
In src/random.c, make Random32 (and Random2_32) reuse sRngLoopUnlocked around the state update, matching LOOP_RANDOM_START/END; keep AdvanceRandom skipping when the lock is held.

Done when
A test in test/random.c that calls Random32 in a tight loop while VBlank AdvanceRandom is enabled never observes a gRngValue that is not a valid successor of the previous state.

Lead check: snippet present at src/random.c:45; claim confirmed.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions