Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HardFault with capnp and no_std #293

Closed
guillaume-michel opened this issue Sep 6, 2022 · 12 comments
Closed

HardFault with capnp and no_std #293

guillaume-michel opened this issue Sep 6, 2022 · 12 comments

Comments

@guillaume-michel
Copy link

I am playing with capnp on embedded device in Rust. I have setup a playground to evaluate capnp here.

It is a no_std application with a global allocator provided by alloc-cortex-m crate. I have check that the global allocator is working: I can use alloc::vec::Vec and the oom handler is called when memory is exceeded.

The following code, leads to a hard fault but I have no clue how to fix it.

@0x9663f4dd604afa35;

struct DistanceResponse {
  distance @0 : Float32;
}
    use commands_capnp::distance_response;
    let mut message = ::capnp::message::Builder::new_default();
    {
        let mut cmd: distance_response::Builder = message.init_root::<distance_response::Builder>(); // <- hard fault here
        cmd.set_distance(2.0_f32);
    }

The error is the following:

    Finished dev [optimized + debuginfo] target(s) in 0.55s
     Running `probe-run --chip STM32F446RETx target/thumbv7em-none-eabihf/debug/test_capnp`
(HOST) INFO  flashing program (31 pages / 31.00 KiB)
(HOST) INFO  success!
────────────────────────────────────────────────────────────────────────────────
Hello, world!
└─ test_capnp::__cortex_m_rt_main @ src/bin/test_capnp.rs:19
────────────────────────────────────────────────────────────────────────────────
stack backtrace:
   0: HardFaultTrampoline
      <exception entry>
   1: capnp::private::layout::WirePointer::kind
        at /home/gmichel/.cargo/registry/src/github.com-1ecc6299db9ec823/capnp-0.14.9/src/private/layout.rs:148:31
   2: capnp::private::layout::wire_helpers::zero_object
        at /home/gmichel/.cargo/registry/src/github.com-1ecc6299db9ec823/capnp-0.14.9/src/private/layout.rs:517:15
   3: core::cmp::impls::<impl core::cmp::PartialOrd for isize>::lt
        at /rustc/cacc75c82ebe15cf63d31034fcf7f1016cddf0e2/library/core/src/cmp.rs:1398:52
   4: <core::ops::range::Range<T> as core::iter::range::RangeIteratorImpl>::spec_next
        at /rustc/cacc75c82ebe15cf63d31034fcf7f1016cddf0e2/library/core/src/iter/range.rs:621:12
   5: core::iter::range::<impl core::iter::traits::iterator::Iterator for core::ops::range::Range<A>>::next
        at /rustc/cacc75c82ebe15cf63d31034fcf7f1016cddf0e2/library/core/src/iter/range.rs:711:9
   6: capnp::private::layout::wire_helpers::zero_object_helper
        at /home/gmichel/.cargo/registry/src/github.com-1ecc6299db9ec823/capnp-0.14.9/src/private/layout.rs:560:26
   7: capnp::private::layout::wire_helpers::allocate
   8: capnp::private::layout::wire_helpers::init_struct_pointer
        at /home/gmichel/.cargo/registry/src/github.com-1ecc6299db9ec823/capnp-0.14.9/src/private/layout.rs:976:14
   9: capnp::private::layout::PointerBuilder::init_struct
        at /home/gmichel/.cargo/registry/src/github.com-1ecc6299db9ec823/capnp-0.14.9/src/private/layout.rs:2692:13
  10: <test_capnp::commands_capnp::distance_response::Builder as capnp::traits::FromPointerBuilder>::init_pointer
        at target/thumbv7em-none-eabihf/debug/build/capnp-playground-48092f26e6a0b1ae/out/capnp/command_capnp.rs:81:47
  11: capnp::any_pointer::Builder::init_as
        at /home/gmichel/.cargo/registry/src/github.com-1ecc6299db9ec823/capnp-0.14.9/src/any_pointer.rs:142:9
  12: capnp::message::Builder<A>::init_root
        at /home/gmichel/.cargo/registry/src/github.com-1ecc6299db9ec823/capnp-0.14.9/src/message.rs:394:9
  13: test_capnp::__cortex_m_rt_main
        at src/bin/test_capnp.rs:37:51
  14: main
        at src/bin/test_capnp.rs:17:1
  15: Reset
(HOST) ERROR the program panicked

Can you help me please?

@guillaume-michel guillaume-michel changed the title HardFault with no_std HardFault with capnp and no_std Sep 6, 2022
@dwrensha
Copy link
Member

dwrensha commented Sep 6, 2022

Hm... I wonder if there's some alignment problem. Have you tried enabling the unaligned feature?

unaligned = []

@guillaume-michel
Copy link
Author

Thanks for your quick response. I tried to add the unaligned feature to capnp but still the same error.

capnp = { version = "0.14.9", default-features = false, features = ["unaligned"] }

@dwrensha
Copy link
Member

dwrensha commented Sep 7, 2022

I can use alloc::vec::Vec and the oom handler is called when memory is exceeded

Can you successfully get and set values in the Vec?

@guillaume-michel
Copy link
Author

Sorry for the delay in the response.

Yes, I can set and get values back from a Vec:

#[macro_use]
extern crate alloc;

use alloc::vec::Vec;

// ...

// test if we can put value in Vec then read them back
    {
        let values: Vec<_> = vec![1, 2, 3, 4];
        assert_eq!(values[0], 1);
        assert_eq!(values[1], 2);
        assert_eq!(values[2], 3);
        assert_eq!(values[3], 4);

        defmt::info!("Vec test complete"); // this logs appears
    }

@dwrensha
Copy link
Member

Someone else reported a hard fault when using alloc-cortex-m last year: #221 (comment)

I do happen to have a cortex M4 here. I'll try to reproduce the issue on it (but it may be slow going). If there's a way to reproduce the issue in Linux (like via an emulator) that would be potentially helpful.

@guillaume-michel
Copy link
Author

I had a look at Qemu and it seams it only support 2 boards from Ti for Cortex-M4. Mine is a NUCLEO-F446RE and I have no experience on Ti hardware.

If you tell me which board you have, I may be able to help you setup the board or buy the board, set it up and modify the example code accordingly. I can also ship you the same board as mine, so you can run the firmware from the provided github repo as is.

Let me know which way you prefer?

@dwrensha
Copy link
Member

I'm poking around on qemu right now. The two relevant pieces of hardware that I have are: a Neotrellis M4 https://www.adafruit.com/product/4020 and a Gemma M0 https://www.adafruit.com/product/3501.

@guillaume-michel
Copy link
Author

I am not at all familiar with these boards. Maybe the best course of action is me sending you the relevant hardware.

@dwrensha
Copy link
Member

aha! We need to check the result of alloc_zeroed():

let ptr = unsafe {
alloc::alloc::alloc_zeroed(alloc::alloc::Layout::from_size_align(size as usize * BYTES_PER_WORD, 8).unwrap())
};

In your example, the heap size is too small for message::Builder::new_default(). https://github.com/guillaume-michel/capnp_playground/blob/b7b34c65cdd51f7a5842526f1c81d3dfbd1a28be/src/bin/test_capnp.rs#L24

@dwrensha
Copy link
Member

Should be fixed in 8c9d41b.

@guillaume-michel
Copy link
Author

guillaume-michel commented Sep 21, 2022

Thanks! That was it!

For future reference, it looks like Cap'n Proto is trying to allocate 8kB on the heap but my heap was only 4kB in size. The fix, clearly identifies the problem with an error message.

With the fix (0.14.10) and a heap of 4kB, my alloc_error_handler is called and this is the log I have:

0.000145 ERROR Could not allocate memory with layout: Layout { size: 8192, align: 8 }
0.000183 INFO  Global allocator state: used 0 - free: 4096

Increasing the size on the heap in my application to a value larger than 8kB fixed the problem.

I looks strange to me that 8kB is needed for such small messages but this question is for an other time. For the time beeing, I can live with it.

Again, Thank you for you prompt help and fix!

@dwrensha
Copy link
Member

You can allocate less memory for the first segment by doing something like this (instead of message::Builder::new_default()):

let mut message = message::Builder::new(message::HeapAllocator::new().first_segment_words(256));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants