esp-rs / esp32-hal

A hardware abstraction layer for the esp32 written in Rust.
Apache License 2.0
193 stars 28 forks source link

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

Closed bjoernQ closed 2 years ago

bjoernQ commented 2 years ago

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 https://github.com/esp-rs/esp32-hal/blob/17e9fd7cfa7bc675eba4f06e7a7b59ccc8910330/examples/timer.rs#L174 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?

MabezDev commented 2 years ago

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.

bjoernQ commented 2 years ago

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

bjoernQ commented 2 years ago

Closed by https://github.com/esp-rs/xtensa-lx-rt/pull/34