japaric / cargo-call-stack

Whole program static stack analysis
Apache License 2.0
579 stars 52 forks source link

Panic!() Function in Analyzed Code causes Assertion Errors in Cargo-Call-Stack #24

Closed DrTobe closed 2 years ago

DrTobe commented 4 years ago

When I was trying Cargo-Call-Stack in my project, it failed with the following error message:

...
thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `56`,
 right: `52`: BUG: LLVM reported that `_ZN50_$LT$$RF$mut$u20$W$u20$as$u20$core..fmt..Write$GT$9write_fmt17h0763000cb7e29fb5E` uses 52 bytes of stack but this doesn't match our analysis', .../.cargo/registry/src/github.com-1ecc6299db9ec823/cargo-call-stack-0.1.4/src/main.rs:1001:29

I could narrow down this problem and found that it seems to be related to the panic-handler implementations that several crates offer for embedded development. Comparing the four options listed in the Embedded Rust Book, I got the results that I documented in the following example code:

#![no_main]
#![no_std]

use cortex_m_rt::entry;
extern crate nucleo_f401re;

use panic_semihosting as _; // cargo-call-stack assertion error
//use panic_itm as _;       // cargo-call-stack assertion error
//use panic_halt as _;      // OK
//use panic_abort as _;     // OK

#[entry]
fn main() -> ! {
    panic!("Test panic behavior.");
}

I do not know if there is a simple explanation why this has to fail there or if that is a bug, I just wanted to let you know. If you need further information, please let me know. If it is of any help, my current setup is:

JOE1994 commented 4 years ago

This issue persists in the following setup:

jhbruhn commented 2 years ago

Can confirm with

[2022-01-19T23:43:28Z WARN  cargo_call_stack] assuming that asm!("push {r4, lr}\0Asub sp, sp, #16\0Aadd r4, sp, #8\0Astr r4, [sp]\0Abl __udivmoddi4\0Aldr r2, [sp, #8]\0Aldr r3, [sp, #12]\0Aadd sp, sp, #16\0Apop {r4, pc}") does *not* use the stack in `__aeabi_uldivmod`
thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `16`,
 right: `8`: BUG: LLVM reported that `_ZN4core9panicking9panic_str17hda8969b1b2a19f41E` uses 16 bytes of stack but this doesn't match our analysis', /home/jhbruhn/.cargo/registry/src/github.com-1ecc6299db9ec823/cargo-call-stack-0.1.6/src/main.rs:851:29
stack backtrace:
   0: rust_begin_unwind
             at /rustc/c8dfcfe046a7680554bf4eb612bad840e7631c4b/library/std/src/panicking.rs:515:5
   1: core::panicking::panic_fmt
             at /rustc/c8dfcfe046a7680554bf4eb612bad840e7631c4b/library/core/src/panicking.rs:92:14
   2: core::panicking::assert_failed_inner
   3: core::panicking::assert_failed
   4: cargo_call_stack::run
   5: cargo_call_stack::main

This happens in a setup similar to the one demonstrated in this issues description.

The panic handler:

#[inline(never)]
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
    static PANICKED: AtomicBool = AtomicBool::new(false);

    cortex_m::interrupt::disable();

    // Guard against infinite recursion, just in case.
    if PANICKED.load(Ordering::Relaxed) {
        loop {
            cortex_m::asm::bkpt();
        }
    }

    PANICKED.store(true, Ordering::Relaxed);

    // Trigger a `HardFault` via `udf` instruction.

    // If `UsageFault` is enabled, we disable that first, since otherwise `udf` will cause that
    // exception instead of `HardFault`.
    const SHCSR: *mut u32 = 0xE000ED24usize as _;
    const USGFAULTENA: usize = 18;

    unsafe {
        let mut shcsr = core::ptr::read_volatile(SHCSR);
        shcsr &= !(1 << USGFAULTENA);
        core::ptr::write_volatile(SHCSR, shcsr);
    }

    cortex_m::asm::udf();
}
japaric commented 2 years ago

this report is pretty old but I cannot reproduce the problem with the given instructions. if you run into issues with the latest version of cargo-call-stack please open a new issue.

$ cargo generate --git https://github.com/rust-embedded/cortex-m-quickstart --name app
$ cd app

$ rg '^target' .cargo/config.toml
37:target = "thumbv7em-none-eabihf"

$ cat src/main.rs
#![no_std]
#![no_main]

use panic_semihosting as _;

use cortex_m_rt::entry;
use nucleo_f401re as _;

#[entry]
fn main() -> ! {
    panic!("Test panic behavior.");
}
$ rg -A1 '^name = "panic-semihosting"' Cargo.lock
198:name = "panic-semihosting"
199-version = "0.6.0"

$ rg -A1 '^name = "nucleo-f401re"' Cargo.lock
180:name = "nucleo-f401re"
181-version = "0.4.1"

$ cargo call-stack --bin app > /tmp/cg.dot && echo OK
(..)
OK

$ cargo call-stack --version
cargo-call-stack 0.1.12

$ rustc -V
rustc 1.67.0-nightly (96ddd32c4 2022-11-14)

(image intentionally scaled down) out