Skip to content

Deserializing a sparse map panics because capacity is derived from the entry count #191

Description

@RAprogramm

The Deserialize implementation builds the target map with Map::with_capacity_none(map.len()) and then inserts every entry by its original key. For a sparse map the highest key is larger than the number of entries, so the insert crosses the boundary and panics.

Reproduction

let mut before: Map<u8> = Map::with_capacity_none(32);
before.insert(0, 1);
before.insert(31, 2);
let bytes: Vec<u8> = bincode::serialize(&before).unwrap();
let after: Map<u8> = bincode::deserialize(&bytes).unwrap();

Result: The key 31 is over the boundary 2.

Two more gaps in the same code path

  • usize::MAX is reserved internally as the NodeId::UNDEF sentinel, but the visitor accepts it as a key.
  • max_key + 1 is used as the capacity without checking that Layout::array::<Node<V>> can represent it, so a crafted payload turns into an allocation failure instead of a deserialization error.

Expected

  • Capacity is max_key + 1, so every entry is inserted at its original key.
  • A usize::MAX key is rejected with a serde error.
  • A capacity that exceeds the addressable range is rejected with a serde error.

Plan

  • Collect entries and track the maximum key, then allocate max_key + 1.
  • Reject the reserved key and the oversized layout with serde::de::Error::custom.
  • Cover the round trip, the sparse case and both rejections with tests.

@yegor256, please take a look.

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