-
Notifications
You must be signed in to change notification settings - Fork 390
Open
Description
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
- 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);
}
- 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):
- It gets wrapped:
0x0900 % 0x0900 = 0x0000
- Then
0x0000 < 32
triggers the crash - 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
Labels
No labels