feat(core/rust): improve panic UX in case Rust heap allocation fails
What changed, and why it matters
This commit changes how a Trezor hardware wallet's Rust code reacts when it runs out of memory. Previously, a failed memory allocation returned a null pointer, which could later trigger a confusing internal panic from the Rust standard library. Now, the device immediately reports a clear 'Allocation failed' fatal error instead. The change is framed as a user-experience improvement, not as fixing a security vulnerability, and it does not make attacks easier.
Treat as a minor hardening/UX change rather than a security patch. Continue normal review and testing. If auditing memory handling, verify that all Rust code paths handle the new fatal-error behavior correctly and that no safety-critical code relied on the previous null-return semantics.
Security signals we found
Change converts a null-return OOM path into an immediate fatal error
Removes a code path where Rust stdlib could panic internally on allocation failure
No new bounds checks, input validation, or memory-zeroing added
No changelog entry; commit is described as UX improvement
Evidence from the diff
In core/embed/rust/src/micropython/tracked_allocator.rs, the custom GlobalAlloc::alloc implementation for the Rust heap no longer silently returns a null pointer when ffi::m_tracked_calloc fails. It now calls ensure!(!raw.is_null(), "Allocation failed"), which aborts with a fatal error. The debug logging and alignment check are moved so they run only after a successful allocation. This converts a potential delayed Rust stdlib out-of-memory panic into an immediate, labeled failure.
Changed components
core/embed/rust/src/micropython/tracked_allocator.rsRust heap allocator on Trezor devicesInspect captured patch +12 / −11
### core/embed/rust/src/micropython/tracked_allocator.rs
@@ -21,18 +21,19 @@ unsafe impl GlobalAlloc for TrackedAllocator {
// not support custom alignment.
// - `raw` is guaranteed to stay valid as long as `m_tracked_free()` is not
// called.
- // EXCEPTION: Returns null instead of raising.
+ // EXCEPTION:
+ // - Terminates with a fatal error if allocation fails (better UX, instead of an
+ // internal Rust stdlib panic).
let raw: *mut c_void = unsafe { ffi::m_tracked_calloc(1, size) };
- if !raw.is_null() {
- #[cfg(feature = "debug")]
- log::trace!(
- "{:?} = {} : +{}",
- raw,
- TOTAL.fetch_add(size, Ordering::Relaxed),
- size
- );
- ensure!(raw.is_aligned_to(layout.align()), "Unaligned allocation");
- }
+ ensure!(!raw.is_null(), "Allocation failed");
+ #[cfg(feature = "debug")]
+ log::trace!(
+ "{:?} = {} : +{}",
+ raw,
+ TOTAL.fetch_add(size, Ordering::Relaxed),
+ size
+ );
+ ensure!(raw.is_aligned_to(layout.align()), "Unaligned allocation");
raw as _
}
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {Why this scored 23/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.