Description
The following code causes UB (found by a patched miri enforcing validity invariants):
let mut b = std::collections::BTreeSet::new();
b.insert(42);
What happens is that BTreeSet::new
sets the root node to a pointer to a static EMPTY_ROOT_NODE
shared for this purpose by all B-trees that has type LeafNode<(), ()>
. That step is okay.
However, in the next step, insert
calls ensure_root_is_owned
which indirectly turns this ptr into &LeafNode<i32, ()>
. The trouble is that LeafNode<i32, ()>
is bigger than LeafNode<(), ()>
, so this reference is partially dangling: Its beginning points to allocated memory (the static EMPTY_ROOT_NODE
), but that allocated memory ends "too early". The invariant that &LeafNode<i32, ()>
be dereferencable for mem::size_of::<LeafNode<i32, ()>>()
bytes is violated. Since we are passing dereferencable(n)
to LLVM with n
set to the full size of the struct, this means we have UB not just according to our own validity rules, but according to LLVM's rules.