#5698·burn

burn-store: Unsound clone_unsafely visitor memcpy causes double-free/UB, and deserializer panics on unsupported types

Author: Sadik00789Created Sep 16, 2026Updated Sep 17, 2026
Labelsbugstore

Describe the bug While auditing burn-store, I identified a critical memory-safety vulnerability in the nested deserializer alongside several process-aborting panic paths.

  1. Unsound unsafe clone in clone_unsafely (Critical / UB) Deserializer::deserialize_enum duplicates the caller's generic Visitor using raw bitwise copying (ptr::copy_nonoverlapping) without requiring a Copy bound:
rust
fn clone_unsafely<T>(thing: &T) -> T {
    unsafe {
        let mut clone = std::mem::MaybeUninit::<T>::uninit();
        ptr::copy_nonoverlapping(thing as *const T, clone.as_mut_ptr(), 1);
        clone.assume_init()
    }
}

Impact: Because Visitor is not Copy, any non-ZST visitor carrying heap allocations (e.g., a Vec or String) aliases the same memory address across two owners, leading to a double-free / use-after-free when both instances drop.

Miri Verification: Reproduced under Miri (nested_de_miri.rs), which flags an immediate dangling reference/use-after-free error.

  1. Recoverable Errors Treated as Process Panics (High) The nested deserializer turns valid data errors into hard process aborts via unimplemented!():
  • deserialize_any() panics on untagged enums, #[serde(flatten)], or dynamic values.
  • deserialize_i8() and deserialize_u32() panic due to incomplete primitive dispatch symmetry.
  • tuple_variant() / struct_variant() panic on data-carrying enum variants.

To Reproduce Steps to reproduce the behavior:

  1. Implement a custom non-ZST Serde Visitor owning a heap allocation (e.g., a Vec<String>).
  2. Pass it to Deserializer::deserialize_enum within burn-store.
  3. Run under Miri: cargo +nightly miri test -p burn-store --test nested_de_miri.
  4. See use-after-free / double-free UB error.

Expected behavior Deserializer should safely handle enum variants and visitors without unsafe memory aliasing, and unsupported types or variant paths should return a recoverable serde::de::Error rather than aborting the process with a panic.

Desktop :

  • OS: Fedora Linux
  • Rust Version: Nightly / Stable

Proposed Solution:

  • Remove clone_unsafely entirely from de.rs and refactor deserialize_enum to evaluate variant access safely without cloning the visitor.
  • Replace unimplemented!() paths in primitives and enum dispatchers with proper Err(serde::de::Error::custom(...)) returns.