trussed-dev/littlefs2

Rust 1.67.0 breaks unit tests

robin-nitrokey opened this issue · 6 comments

---- fs::tests::remove_dir_all stdout ----
generated PathBuf dir p"\0" using i = 0
creating p"\0"
generated PathBuf dir p"/tmp\0" using i = 4
creating p"/tmp\0"
creating p"/tmp/test\0"
thread 'fs::tests::remove_dir_all' panicked at 'already borrowed: BorrowMutError', src/fs.rs:1218:29
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

---- fs::tests::todo stdout ----
blocks going in: 6
generated PathBuf dir p"\0" using i = 0
creating p"\0"
generated PathBuf dir p"/tmp\0" using i = 4
creating p"/tmp\0"
creating p"/tmp/test\0"
thread 'fs::tests::todo' panicked at 'already borrowed: BorrowMutError', src/fs.rs:1218:29

---- tests::test_create stdout ----
creating p"/tmp\0"
thread 'tests::test_create' panicked at 'already borrowed: BorrowMutError', src/fs.rs:284:69

---- tests::test_fs_with stdout ----
creating p"/tmp\0"
thread 'tests::test_fs_with' panicked at 'already borrowed: BorrowMutError', src/fs.rs:284:69

Very odd. Here's a somewhat minimal failing test:

fn minimal() {
    let mut backend = OtherRam::default();
    let mut storage = OtherRamStorage::new(&mut backend);

    Filesystem::format(&mut storage).unwrap();
    Filesystem::mount_and_then(&mut storage, |fs| {
        fs.create_dir(b"/tmp\0".try_into().unwrap()).unwrap();
        fs.available_blocks().ok();
        Ok(())
    }).unwrap();
}

Both create_dir and available_blocks do a self.alloc.borrow_mut(), to pass in .state to ll:lfs_*. Even explicitly dropping these &mut self.alloc.borrow_mut().state doesn't fix.

@sosthene-nitrokey suggested that this may be caused by a struct with an undefined representation being used in the FFI causing undefined behavior as this is known to break stuff with 1.67.0.

https://octodon.social/@rust/109759251309886588
https://old.reddit.com/r/rust/comments/10lu5ah/announcing_rust_1670/j5z8rk4/?context=3

But as far as I see, all relevant structs already have #[repr(C)]. Strangely, using RUSTFLAGS="-Z randomize-layout" cargo +nightly test seemed to fix the problem though it should potentially make it worse.

I think I found the issue. It looks like this is just the lookahead buffer issue in disguise – the buffer overflow just manifests differently with 1.67.0. Fixed by #24.

Can also manifest as a segfault (e. g. if compiled with --release):

signal: 11, SIGSEGV: invalid memory reference

Oh, so it's our bug, and not a compiler regression?

Yes, I think so. The layout changes in Rust 1.67.0 probably just cause us to access a different memory region causing a different error.