Skip to content

Serializing NaiveDatetime on AVR crashes #99

@rihardsk

Description

@rihardsk

Whenever i try to serialize a chrono::NaiveDateTime or any struct that contains it internally, the program resets, if it's being run on an AVR microcontroller (ATmega328p specifically). It can be as simple as:

let entry = NaiveDateTime::MIN;
// This is where it crashes and the board resets and restarts running from the beginning
let output: postcard::Result<Vec<u8, 64>> = to_vec(&entry);

Serializing other stuff seems to work fine, e.g., this example code from the docs works as expected:

#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
struct RefStruct<'a> {
    bytes: &'a [u8],
    str_s: &'a str,
}

let message = "hElLo";
let bytes = [0x01, 0x10, 0x02, 0x20];
let output: postcard::Result<Vec<u8, 11>> = to_vec(&RefStruct {
    bytes: &bytes,
    str_s: message,
});

Also, the same code runs without issue on x64, which makes me suspect a miscompilation on AVR but verifying that seems to be beyond my ability currently (tried looking at the AVR disassembly but there's simply too much going on there).

I'm building the code using the nightly-2023-03-24 toolchain.

Minimal reproducible example

main.rs

#![no_std]
#![no_main]

use chrono::NaiveDateTime;
use serde::{Deserialize, Serialize};

use heapless::Vec;
use panic_halt as _;
use postcard::to_vec;

#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
struct RefStruct<'a> {
    bytes: &'a [u8],
    str_s: &'a str,
}

#[arduino_hal::entry]
fn main() -> ! {
    let dp = arduino_hal::Peripherals::take().unwrap();
    let pins = arduino_hal::pins!(dp);

    let mut serial = arduino_hal::default_serial!(dp, pins, 9600);

    ufmt::uwriteln!(&mut serial, "Serial set up, entering loop").unwrap();

    arduino_hal::delay_ms(1000);
    loop {
        let entry = NaiveDateTime::MIN;

        ufmt::uwriteln!(&mut serial, "Converting").unwrap();
        arduino_hal::delay_ms(1000);

        // For some reason this serialization code works ...
        //
        // let message = "hElLo";
        // let bytes = [0x01, 0x10, 0x02, 0x20];
        // let output: postcard::Result<Vec<u8, 11>> = to_vec(&RefStruct {
        //     bytes: &bytes,
        //     str_s: message,
        // });

        // ... but this doesn't
        //
        // NOTE: Not sure how much memory this takes but 64 bytes should be
        // plenty for serialization, i guess
        let output: postcard::Result<Vec<u8, 64>> = to_vec(&entry);

        ufmt::uwriteln!(&mut serial, "Writing").unwrap();
        arduino_hal::delay_ms(1000);
        match output {
            Ok(output) => {
                for byte in output {
                    serial.write_byte(byte);
                }
                serial.flush();
            }
            Err(_e) => ufmt::uwriteln!(&mut serial, "Serialization error").unwrap(),
        }

        arduino_hal::delay_ms(5000);
    }
}

Cargo.toml

[package]
name = "templog-arduino"
version = "0.1.0"
edition = "2021"
license = "MIT OR Apache-2.0"

[[bin]]
name = "templog-arduino"
test = false
bench = false

[dependencies]
panic-halt = "0.2.0"
ufmt = "0.1.0"
embedded-hal = "0.2.3"
serde = { version = "1.0.147", features = ["derive"], default-features = false }
chrono = { version = "0.4.23", features = ["serde"], default-features = false }
heapless = { git = "https://github.com/japaric/heapless" }

[dependencies.postcard]
# this refers to postcard rev 62c05473f76ead781aaa9d4a3e4057b86e543747
# with an updated version of `heapless` dependency
path = "../../postcard"

[dependencies.arduino-hal]
git = "https://github.com/rahix/avr-hal"
rev = "3b8f39fa2ec5e3359c7bedc33d982e75e8cc3700"
features = ["arduino-uno"]

# This doesn't seem to have any effect, don't know why
# [patch.crates-io]
# heapless = { git = 'https://github.com/japaric/heapless' }

# Configure the build for minimal size - AVRs have very little program memory
[profile.dev]
panic = "abort"
lto = true
opt-level = "s"

[profile.release]
panic = "abort"
codegen-units = 1
debug = true
lto = true
opt-level = "s"

Other things to note

I'm using postcard rev 62c05473f76ead781aaa9d4a3e4057b86e543747 with the following diff applied to it to work around #82

diff --git a/Cargo.toml b/Cargo.toml
index 6498e55..d16e0dd 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -29,7 +29,8 @@ version = "0.2.24"
 optional = true
 
 [dependencies.heapless]
-version = "0.7.0"
+# version = "0.7.0"
+git = 'https://github.com/japaric/heapless'
 default-features = false
 features = ["serde"]
 optional = true

heapless is at rev 644653bf3b831c6bb4963be2de24804acf5e5001.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions