Skip to content

Commit ddacf03

Browse files
committed
Make into_key_slice avoid taking out-of-bounds pointers
1 parent 5b94e9f commit ddacf03

File tree

1 file changed

+34
-14
lines changed

1 file changed

+34
-14
lines changed

src/liballoc/btree/node.rs

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -107,10 +107,12 @@ impl<K, V> LeafNode<K, V> {
107107
}
108108
}
109109

110-
// We need to implement Sync here in order to make a static instance
110+
// We need to implement Sync here in order to make a static instance.
111111
unsafe impl Sync for LeafNode<(), ()> {}
112112

113-
// An empty node used as a placeholder for the root node, to avoid allocations
113+
// An empty node used as a placeholder for the root node, to avoid allocations.
114+
// We use () in order to save space, since no operation on an empty tree will
115+
// ever take a pointer past the first key.
114116
static EMPTY_ROOT_NODE: LeafNode<(), ()> = LeafNode {
115117
parent: ptr::null(),
116118
parent_idx: 0,
@@ -539,26 +541,39 @@ impl<'a, K, V, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
539541
}
540542
}
541543

542-
pub fn keys_mut(&mut self) -> &mut [K] {
544+
fn keys_mut(&mut self) -> &mut [K] {
543545
unsafe { self.reborrow_mut().into_key_slice_mut() }
544546
}
545547

546-
pub fn vals_mut(&mut self) -> &mut [V] {
548+
fn vals_mut(&mut self) -> &mut [V] {
547549
unsafe { self.reborrow_mut().into_val_slice_mut() }
548550
}
549551
}
550552

551553
impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Immut<'a>, K, V, Type> {
552554
fn into_key_slice(self) -> &'a [K] {
553-
unsafe {
554-
slice::from_raw_parts(
555-
self.as_leaf().keys.as_ptr(),
556-
self.len()
557-
)
555+
// When taking a pointer to the keys, if our key has a stricter
556+
// alignment requirement than the shared root does, then the pointer
557+
// would be out of bounds, which LLVM assumes will not happen. If the
558+
// alignment is more strict, we need to make an empty slice that doesn't
559+
// use an out of bounds pointer.
560+
if mem::align_of::<K>() > mem::align_of::<LeafNode<(), ()>>() && self.is_shared_root() {
561+
&[]
562+
} else {
563+
// Here either it's not the root, or the alignment is less strict,
564+
// in which case the keys pointer will point "one-past-the-end" of
565+
// the node, which is allowed by LLVM.
566+
unsafe {
567+
slice::from_raw_parts(
568+
self.as_leaf().keys.as_ptr(),
569+
self.len()
570+
)
571+
}
558572
}
559573
}
560574

561575
fn into_val_slice(self) -> &'a [V] {
576+
debug_assert!(!self.is_shared_root());
562577
unsafe {
563578
slice::from_raw_parts(
564579
self.as_leaf().vals.as_ptr(),
@@ -583,15 +598,20 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
583598
}
584599

585600
fn into_key_slice_mut(mut self) -> &'a mut [K] {
586-
unsafe {
587-
slice::from_raw_parts_mut(
588-
&mut self.as_leaf_mut().keys as *mut [K] as *mut K,
589-
self.len()
590-
)
601+
if mem::align_of::<K>() > mem::align_of::<LeafNode<(), ()>>() && self.is_shared_root() {
602+
&mut []
603+
} else {
604+
unsafe {
605+
slice::from_raw_parts_mut(
606+
&mut self.as_leaf_mut().keys as *mut [K] as *mut K,
607+
self.len()
608+
)
609+
}
591610
}
592611
}
593612

594613
fn into_val_slice_mut(mut self) -> &'a mut [V] {
614+
debug_assert!(!self.is_shared_root());
595615
unsafe {
596616
slice::from_raw_parts_mut(
597617
&mut self.as_leaf_mut().vals as *mut [V] as *mut V,

0 commit comments

Comments
 (0)