Skip to content

False positive crash: "low registers" error on wrapped out-of-bounds writes #560

@m3y54m

Description

@m3y54m

Description

Simavr incorrectly crashes with a "low registers" error when out-of-bounds memory writes are wrapped into the low register address range (< 32). The actual issue is the out-of-bounds write itself, but the error message is misleading.

How to Reproduce

  1. Create test_bug.c:
#include <avr/io.h>

int main(void) {
    // ATmega328p ramend = 0x08ff
    // Writing to 0x0900 wraps to 0x00
    volatile uint8_t *ptr = (volatile uint8_t *)0x0900;
    *ptr = 0x42;
    while(1);
}
  1. Compile and run:
avr-gcc -mmcu=atmega328p -Os test_bug.c -o test_bug.elf
avr-objcopy -O ihex test_bug.elf test_bug.hex
simavr -m atmega328p -f 16000000 test_bug.hex

Expected Behavior

Simavr should either:

  • Report a warning about out-of-bounds write to address 0x0900, or
  • Continue execution after wrapping the address

Actual Behavior

Simavr crashes with a "low registers" error for address 0000, but the actual problem is an out-of-bounds write to 0x0900 that got wrapped to 0x0000.

Loaded 140 bytes of Flash data at 0
CORE: *** Invalid write address PC=0082 SP=08fd O=9380 Address 0000=42 low registers
avr_sadly_crashed

Root Cause

In simavr/sim/sim_core.c:227, the avr_core_watch_write() function checks for low register writes after wrapping out-of-bounds addresses:

if (addr > avr->ramend) {
    addr = addr % (avr->ramend + 1);  // Wrap first
}
if (addr < 32) {
    crash(avr);  // Check after wrapping → false positive
}

When addr = 0x0900 (out-of-bounds):

  1. It gets wrapped: 0x0900 % 0x0900 = 0x0000
  2. Then 0x0000 < 32 triggers the crash
  3. Error message reports "low registers" instead of "out-of-bounds write"

UPDATE:

Main Root Cause:

  • Issue 1: Incorrect wrapping formula (addr % (ramend+1)) wrapped to registers instead of RAM
  • Issue 2: Impossible safety check (addr < 32) that could never trigger normally, only after bad wrapping
  • Result: False positive crashes

Proposed Solution

Check for low register access before any address modification:

if (addr < 32) {
    crash(avr);  // Check first
}
if (addr > avr->ramend) {
    addr = addr % (avr->ramend + 1);  // Wrap after
}

UPDATE:

Final Proposed Fix:

  • Correct wrapping formula: ramstart + ((addr - ramstart) % ramsize)
  • Wraps within RAM space (0x0100-0x08FF), not into registers

Impact

  • Misleading error messages make debugging difficult
  • Code that works on real AVR hardware crashes in simavr

Environment

  • simavr version: master (latest)
  • Target MCU: ATmega328p
  • Platform: Linux
  • Affected file: simavr/sim/sim_core.c

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions