fix(diagnostics): bound formatting and release ingress before callbacks

Bound UTF-8 formatting and release diagnostic ingress before invoking
callbacks. Check error-ID collisions at Rust/C++ release final link.

Validation: diagnostic tests, strict Clippy, Miri and final-link cases.
This commit is contained in:
Onur Özkan committed 2026-11-07 18:12:11 +03:00
1 parent 3226ef97fe
commit 84807dde4e
12 files changed
+547 -48

No files matched your search

@@ -78,6 +78,54 @@ mod tests {
use super::ErrorIngress;
use crate::ErrorId;
#[test]
fn concurrent_publication_and_take_preserve_complete_unique_records() {
let ingress = ErrorIngress::new();
let start = std::sync::Barrier::new(3);
let mut records = std::thread::scope(|scope| {
let ingress = &ingress;
let start = &start;
let producers: [_; 2] = core::array::from_fn(|producer| {
scope.spawn(move || {
start.wait();
for sequence in 0..8 {
ingress.publish(
ErrorId::new(1000 + (producer * 8 + sequence) as u16),
["left", "right"][producer],
);
std::thread::yield_now();
}
})
});
let consumer = scope.spawn(move || {
start.wait();
let mut records = std::vec::Vec::new();
for _ in 0..64 {
records.extend(ingress.take());
std::thread::yield_now();
}
records
});
for producer in producers {
producer.join().unwrap();
}
consumer.join().unwrap()
});
records.extend(ingress.take());
assert!(ingress.take().is_none());
assert!(!records.is_empty());
// Contention may discard publications. Every retained record must be
// one complete publication, and it may be consumed only once.
let mut seen = [false; 16];
for record in records {
let index = usize::from(record.id().checked_sub(1000).unwrap());
assert!(index < seen.len());
assert_eq!(record.raised_at(), ["left", "right"][index / 8]);
assert!(!core::mem::replace(&mut seen[index], true));
}
}
#[test]
fn retains_the_first_id_and_location_until_consumed() {
let ingress = ErrorIngress::new();
@@ -1,8 +1,5 @@
//! Stable reportable firmware errors with bounded diagnostic ingress.
//!
//! This crate owns error identity and ingress. It contains no logging levels,
//! filtering, MAVLink, board, filesystem, or clock dependency.
//!
//! `#[propagate]` turns an annotated function into a reporting point. When a
//! reportable error leaves that function, the macro makes one reporting
//! attempt. Nested annotated callers would therefore attempt to report the