Four code paths create a pointer whose permission is later revoked, then
write through it. Miri reports each as undefined behaviour under both the
Tree Borrows and Stacked Borrows aliasing models (CWE-758). All four are
reachable from safe code with standard Ord types.
split_off, split_off_index and append stored
the first spliced node's prev pointer from a reference to the head, then
wrote through that same reference, invalidating the stored pointer. A later
pop_first or pop_front writes through it. This affects all four
collections.SkipMap::range_mut back pointer. With an Included or Excluded
upper bound, the back pointer came from a shared reference. next_back
hands out &mut V through it, and writing to that value is undefined
behaviour.IterMut::next_back reads a yielded node. In SkipList and SkipMap,
next_back read the predecessor node even after the front end had yielded
it as &mut. The read freezes the caller's reference, and the caller's
next write through it is undefined behaviour. This affects iter_mut,
values_mut and range_mut used from both ends.lower_bound_mut and upper_bound_mut on
OrderedSkipList and SkipSet (cursor feature) took the cursor's list
pointer, then searched through &self. A comparator with interior-mutable
state, such as a Cell call counter, wrote to the list's memory through
that shared borrow and invalidated the cursor's pointer. The comparator can
be a fully consistent order. SkipMap cursors are not affected.No miscompilation has been observed in an optimised build. A future compiler may still optimise on the violated aliasing assumptions.
The flaws were corrected in 1.3.0. Each fix derives the pointer used for mutation from the collection's long-lived allocation pointers, and each has a Miri regression test.
{
"license": "CC0-1.0"
}{
"affected_functions": null,
"affects": {
"arch": [],
"functions": [
"skiplist::ordered_skip_list::OrderedSkipList::append",
"skiplist::ordered_skip_list::OrderedSkipList::lower_bound_mut",
"skiplist::ordered_skip_list::OrderedSkipList::split_off",
"skiplist::ordered_skip_list::OrderedSkipList::split_off_index",
"skiplist::ordered_skip_list::OrderedSkipList::upper_bound_mut",
"skiplist::skip_list::SkipList::append",
"skiplist::skip_list::SkipList::iter_mut",
"skiplist::skip_list::SkipList::range_mut",
"skiplist::skip_list::SkipList::split_off",
"skiplist::skip_map::SkipMap::append",
"skiplist::skip_map::SkipMap::iter_mut",
"skiplist::skip_map::SkipMap::range_mut",
"skiplist::skip_map::SkipMap::split_off",
"skiplist::skip_map::SkipMap::values_mut",
"skiplist::skip_set::SkipSet::append",
"skiplist::skip_set::SkipSet::lower_bound_mut",
"skiplist::skip_set::SkipSet::split_off",
"skiplist::skip_set::SkipSet::split_off_index",
"skiplist::skip_set::SkipSet::upper_bound_mut"
],
"os": []
}
}