esp-rs / esp32-hal

A hardware abstraction layer for the esp32 written in Rust.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Interesting crash not originating from the HAL but easy to reproduce here

bjoernQ opened this issue · comments

I experienced an interesting crash which doesn't originates in the HAL code but since it's easy to explain how to reproduce it here, I post it in this repository. Since I don't know what really causes the problem, I don't know a much better place to report this anyway.

Actually, I experienced this when doing something without the HAL

To reproduce it just take the timer.rs example and replace

sleep((Hertz(1_000_000) / BLINK_HZ).us());

with a busy loop like for _ in 0..100_000 {}

With that change I quickly get an exception like this
*** PanicInfo { payload: Any { .. }, message: Some(Exception: StoreProhibited, Context { PC: 400f4699, PS: 00060f30, A0: 800d9332, A1: 3ffff9c0, A2: 00000001, A3: 000108ec, A4: 8008376e, A5: 3ffff6e0, A6: 00000000, A7: 10040000, A8: 000108ec, A9: 01010101, A10: 0f0f0f0f, A11: 04444444, A12: 8008376e, A13: 3ffff6a0, A14: 00000000, A15: 10200000, SAR: 00000010, EXCCAUSE: 0000001d, EXCVADDR: 00000001, LBEG: 40079161, LEND: 40079168, LCOUNT: 00000000, THREADPTR: 00000000, SCOMPARE1: 00000000, BR: 00000000, ACCLO: 00000000, ACCHI: 00000000, M0: 00000000, M1: 00000000, M2: 00000000, M3: 00000000, F64R_LO: 00000000, F64R_HI: 00000000, F64S: 00000000, FCR: 00000000, FSR: 00000000, F0: 00000000, F1: 00000000, F2: 00000000, F3: 00000000, F4: 00000000, F5: 00000000, F6: 00000000, F7: 00000000, F8: 00000000, F9: 00000000, F10: 00000000, F11: 00000000, F12: 00000000, F13: 00000000, F14: 00000000, F15: 00000000, reserved: [00000000, 00000000, 00000000, 00000000, 00000000, 00000000, 800d9580], BASESAVE: [3ffff9f0, 3fffff78, 000108ec, 000108ec] }), location: Location { file: "/Users/bquentin/.cargo/registry/src/github.com-1ecc6299db9ec823/xtensa-lx-rt-0.7.0/src/exception/lx6.rs", line: 95, col: 5 } }

Changing the ESP-Rust toolchain to e.g. 1.56.0.1 doesn't change anything. Also, in release mode (certainly the busy loop needs modification to prevent it from getting optimized away) it's the same.

No idea yet what is causing this. As said, it's definitely not the HAL since I first experienced this without the HAL.

I used a generic ESP32 dev-board but I doubt it makes a difference.

Maybe @MabezDev has an idea where to look?

Interesting! I've seen this sort of thing a few times too but I can now reproduce using your example changes.

My exception info:

*** PanicInfo { payload: Any { .. }, message: Some(Exception: LoadProhibited, Context { PC: 400f5603, PS: 00060f30, A0: 800d7c51, A1: 3ffffa00, A2: 00000001, A3: 3fffff7c, A4: 800d9243, A5: 3ffff730, A6: 3ffb016c, A7: 00000013, A8: 800d803a, A9: 3ffff9c0, A10: 3fffff78, A11: 0000546c, A12: 8008376e, A13: 3ffff6e0, A14: 00000000, A15: 10200000, SAR: 00000010, EXCCAUSE: 0000001c, EXCVADDR: 00000001, LBEG: 40079161, LEND: 40079168, LCOUNT: 00000000, THREADPTR: 00000000, SCOMPARE1: 00000000, BR: 00000000, ACCLO: 00000000, ACCHI: 00000000, M0: 00000000, M1: 00000000, M2: 00000000, M3: 00000000, F64R_LO: 00000000, F64R_HI: 00000000, F64S: 00000000, FCR: 00000000, FSR: 00000000, F0: 00000000, F1: 00000000, F2: 00000000, F3: 00000000, F4: 00000000, F5: 00000000, F6: 00000000, F7: 00000000, F8: 00000000, F9: 00000000, F10: 00000000, F11: 00000000, F12: 00000000, F13: 00000000, F14: 00000000, F15: 00000000, reserved: [3ffffa60, 3ffffa64, 3ffffa68, 3fffff58, 3ffffa20, 3ffff9f0, 800d7c31], BASESAVE: [3ffffa30, 3fffff78, 0000546b, 0000546c] }), location: Location { file: "/home/mabez/.cargo/registry/src/github.com-1ecc6299db9ec823/xtensa-lx-rt-0.7.0/src/exception/lx6.rs", line: 95, col: 5 } }

Looking at the disassembly it points me here:

400f55fc <core::cmp::impls::<impl core::cmp::PartialOrd for i32>::lt>:
400f55fc:	006136        	entry	a1, 48
400f55ff:	2129      	s32i.n	a2, a1, 8 # <-- store value of a2 8 bytes offset from the stack pointer
400f5601:	3139      	s32i.n	a3, a1, 12 # <-- store value of a3 on stack too
400f5603:	0288      	l32i.n	a8, a2, 0 # <-- Offending line, try and load the value of the address in a2, into a8
400f5605:	0398      	l32i.n	a9, a3, 0
400f5607:	0a0c      	movi.n	a10, 0
400f5609:	01a9      	s32i.n	a10, a1, 0
400f560b:	1a0c      	movi.n	a10, 1
400f560d:	11a9      	s32i.n	a10, a1, 4
400f560f:	032897        	blt	a8, a9, 400f5616 <core::cmp::impls::<impl core::cmp::PartialOrd for i32>::lt+0x1a>
400f5612:	0188      	l32i.n	a8, a1, 0
400f5614:	1189      	s32i.n	a8, a1, 4
400f5616:	1128      	l32i.n	a2, a1, 4
400f5618:	f01d      	retw.n

It's trying to load the value from the address in a2 (the third argument being an optional offset from the address in a2). Looking at the exception context the address its trying to load from (in a2) is 00000001... which definitely does not look right (looks more like a value than and address)!

Seems very odd that its storing the argument values on the stack, and then trying to use the same argument register as the source address of a load...

It's also worth looking at the signature of core::cmp::PartialOrd's lt method: fn le(&self, other: &i32) -> bool, these arguments should be passed by reference, not value.

I suspect this is probably a codegen bug.

If it helps, I found another way to trigger the exception without involving code from core:

I just add this to the example

fn wait() {
    let mut c: i32 = 0;
    loop {
        let is_lower = lower(&c, &1_000_000);
        if !is_lower {
            break;
        } else {
            c += 1;
        }
    }
}

fn lower(a: &i32, b: &i32) -> bool {
    *a < *b
}

And change the sleep to wait().

I get this exception info:

PanicInfo { payload: Any { .. }, message: Some(Exception: LoadProhibited, Context { PC: 400f536b, PS: 00060f30, A0: 800d9776, A1: 3ffffa70, A2: 00000001, A3: 3f400274, A4: 3ffffa98, A5: 00000000, A6: 000008ff, A7: 00000200, A8: 0007bb49, A9: 000f4240, A10: 00000001, A11: 04444444, A12: 8008376e, A13: 3ffff750, A14: 00000000, A15: 10040000, SAR: 00000010, EXCCAUSE: 0000001c, EXCVADDR: 00000001, LBEG: 40079161, LEND: 40079168, LCOUNT: 00000000, THREADPTR: 00000000, SCOMPARE1: 00000000, BR: 00000000, ACCLO: 00000000, ACCHI: 00000000, M0: 00000000, M1: 00000000, M2: 00000000, M3: 00000000, F64R_LO: 00000000, F64R_HI: 00000000, F64S: 00000000, FCR: 00000000, FSR: 00000000, F0: 00000000, F1: 00000000, F2: 00000000, F3: 00000000, F4: 00000000, F5: 00000000, F6: 00000000, F7: 00000000, F8: 00000000, F9: 00000000, F10: 00000000, F11: 00000000, F12: 00000000, F13: 00000000, F14: 00000000, F15: 00000000, reserved: [00000000, 00000000, 00000000, 00000000, 00000000, 00000000, 800da2f0], BASESAVE: [3ffffaa0, 00000001, 3fffff78, 00000000] }), location: Location { file: "/Users/bquentin/oss/esp/xtensa-lx-rt/src/exception/lx6.rs", line: 95, col: 5 } }

The assembly looks like this:

fn wait() {
400d9760:	006136        	entry	a1, 48
400d9763:	080c      	movi.n	a8, 0
/Users/bquentin/oss/esp/esp32-hal/examples/timer.rs:180
    let mut c: i32 = 0;
400d9765:	2189      	s32i.n	a8, a1, 8
/Users/bquentin/oss/esp/esp32-hal/examples/timer.rs:181
    loop {
400d9767:	ffffc6        	j	400d976a <timer::wait+0xa>
400d976a:	08c1a2        	addi	a10, a1, 8
400d976d:	dbcfb1        	l32r	a11, 400d06ac <_stext+0x68c>
400d9770:	dbd081        	l32r	a8, 400d06b0 <_stext+0x690>
/Users/bquentin/oss/esp/esp32-hal/examples/timer.rs:182
        let is_lower = lower(&c, &1_000_000);
400d9773:	0008e0        	callx8	a8
400d9776:	0a8d      	mov.n	a8, a10
400d9778:	1189      	s32i.n	a8, a1, 4
400d977a:	0c41a2        	s8i	a10, a1, 12
400d977d:	ffffc6        	j	400d9780 <timer::wait+0x20>
400d9780:	1188      	l32i.n	a8, a1, 4
400d9782:	190c      	movi.n	a9, 1
/Users/bquentin/oss/esp/esp32-hal/examples/timer.rs:183
        if !is_lower {
400d9784:	108890        	and	a8, a8, a9
400d9787:	00e816        	beqz	a8, 400d9799 <timer::wait+0x39>
400d978a:	ffffc6        	j	400d978d <timer::wait+0x2d>
/Users/bquentin/oss/esp/esp32-hal/examples/timer.rs:186
            break;
        } else {
            c += 1;
400d978d:	2198      	l32i.n	a9, a1, 8
400d978f:	891b      	addi.n	a8, a9, 1
400d9791:	0189      	s32i.n	a8, a1, 0
400d9793:	0b2897        	blt	a8, a9, 400d97a2 <timer::wait+0x42>
400d9796:	000046        	j	400d979b <timer::wait+0x3b>
/Users/bquentin/oss/esp/esp32-hal/examples/timer.rs:189
        }
    }
}
400d9799:	f01d      	retw.n
/Users/bquentin/oss/esp/esp32-hal/examples/timer.rs:186
            c += 1;
400d979b:	0188      	l32i.n	a8, a1, 0
400d979d:	2189      	s32i.n	a8, a1, 8
/Users/bquentin/oss/esp/esp32-hal/examples/timer.rs:181
    loop {
400d979f:	fff1c6        	j	400d976a <timer::wait+0xa>
400d97a2:	dbc4a1        	l32r	a10, 400d06b4 <_stext+0x694>
400d97a5:	cb1c      	movi.n	a11, 28
400d97a7:	dbc4c1        	l32r	a12, 400d06b8 <_stext+0x698>
400d97aa:	daee81        	l32r	a8, 400d0364 <_stext+0x344>
/Users/bquentin/oss/esp/esp32-hal/examples/timer.rs:186
            c += 1;
400d97ad:	0008e0        	callx8	a8
400d97b0:	0041f0        	break	1, 15

400f5364 <timer::lower>:
timer::lower:
/Users/bquentin/oss/esp/esp32-hal/examples/timer.rs:191
fn lower(a: &i32, b: &i32) -> bool {
400f5364:	006136        	entry	a1, 48
400f5367:	2129      	s32i.n	a2, a1, 8
400f5369:	3139      	s32i.n	a3, a1, 12
/Users/bquentin/oss/esp/esp32-hal/examples/timer.rs:192
    *a < *b
400f536b:	0288      	l32i.n	a8, a2, 0
400f536d:	0398      	l32i.n	a9, a3, 0
400f536f:	0a0c      	movi.n	a10, 0
400f5371:	01a9      	s32i.n	a10, a1, 0
400f5373:	1a0c      	movi.n	a10, 1
400f5375:	11a9      	s32i.n	a10, a1, 4
400f5377:	032897        	blt	a8, a9, 400f537e <timer::lower+0x1a>
400f537a:	0188      	l32i.n	a8, a1, 0
400f537c:	1189      	s32i.n	a8, a1, 4
400f537e:	1128      	l32i.n	a2, a1, 4
/Users/bquentin/oss/esp/esp32-hal/examples/timer.rs:193
}
400f5380:	f01d      	retw.n

At 0x400d06ac there is the address of the value 1_000_000.
At 0x400d06b0 there is the address of the to_lower function

If I understand everything correct here, the generated code doesn't look really wrong