Skip to content

Commit 3d33aab

Browse files
committed
patina_internal_collections: Fix bounds checking in Storage::resize()
## Description Added bounds checking when updating node pointers during resize. Prevents out-of-bounds access to buffer[idx] when indices from old storage exceed new buffer size. Fixes potential panic when resizing to smaller buffers while preserving node relationships (left/right/parent pointers). - [x] Impacts functionality? - [ ] Impacts security? - [ ] Breaking change? - [x] Includes tests? - [ ] Includes documentation? ## How This Was Tested - Unit tests (`cargo test --package patina_internal_collections`) - Added test_resize_preserves_valid_pointers to verify fix ## Integration Instructions - N/A
1 parent f921e1e commit 3d33aab

File tree

1 file changed

+65
-3
lines changed
  • core/patina_internal_collections/src

1 file changed

+65
-3
lines changed

core/patina_internal_collections/src/node.rs

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -218,21 +218,33 @@ where
218218

219219
if let Some(left) = old.left() {
220220
let idx = self.idx(left.as_mut_ptr());
221-
buffer[i].set_left(Some(&buffer[idx]));
221+
if idx < buffer.len() {
222+
buffer[i].set_left(Some(&buffer[idx]));
223+
} else {
224+
buffer[i].set_left(None);
225+
}
222226
} else {
223227
buffer[i].set_left(None);
224228
}
225229

226230
if let Some(right) = old.right() {
227231
let idx = self.idx(right.as_mut_ptr());
228-
buffer[i].set_right(Some(&buffer[idx]));
232+
if idx < buffer.len() {
233+
buffer[i].set_right(Some(&buffer[idx]));
234+
} else {
235+
buffer[i].set_right(None);
236+
}
229237
} else {
230238
buffer[i].set_right(None);
231239
}
232240

233241
if let Some(parent) = old.parent() {
234242
let idx = self.idx(parent.as_mut_ptr());
235-
buffer[i].set_parent(Some(&buffer[idx]));
243+
if idx < buffer.len() {
244+
buffer[i].set_parent(Some(&buffer[idx]));
245+
} else {
246+
buffer[i].set_parent(None);
247+
}
236248
} else {
237249
buffer[i].set_parent(None);
238250
}
@@ -780,4 +792,54 @@ mod tests {
780792
assert_eq!(node2.right_ptr(), r1.as_mut_ptr());
781793
assert_eq!(r1.parent_ptr(), node2.as_mut_ptr());
782794
}
795+
796+
#[test]
797+
fn test_resize_preserves_valid_pointers() {
798+
// Test that resize properly handles node relationships during resize.
799+
// Before the fix, accessing buffer[idx] could panic if idx >= buffer.len()
800+
801+
// Create initial storage
802+
const INITIAL_SIZE: usize = 10;
803+
let mut initial_memory = [0; INITIAL_SIZE * node_size::<usize>()];
804+
let mut storage = Storage::<usize>::with_capacity(&mut initial_memory);
805+
806+
// Add 5 nodes
807+
storage.add(100).unwrap(); // idx 0
808+
storage.add(200).unwrap(); // idx 1
809+
storage.add(300).unwrap(); // idx 2
810+
storage.add(400).unwrap(); // idx 3
811+
storage.add(500).unwrap(); // idx 4
812+
813+
// Set up relationships
814+
unsafe {
815+
let node0 = &mut *storage.get_mut(0).unwrap().as_mut_ptr();
816+
let node1 = &mut *storage.get_mut(1).unwrap().as_mut_ptr();
817+
let node2 = &mut *storage.get_mut(2).unwrap().as_mut_ptr();
818+
819+
node0.set_left(Some(node1));
820+
node0.set_right(Some(node2));
821+
node1.set_parent(Some(node0));
822+
node2.set_parent(Some(node0));
823+
}
824+
825+
// Resize to larger buffer
826+
const LARGER_SIZE: usize = 20;
827+
let mut larger_memory = [0; LARGER_SIZE * node_size::<usize>()];
828+
storage.resize(&mut larger_memory);
829+
830+
// Verify relationships are preserved
831+
let node0 = storage.get(0).unwrap();
832+
assert!(node0.left().is_some());
833+
assert!(node0.right().is_some());
834+
835+
// Resize back to exact size (5 nodes in use)
836+
const EXACT_SIZE: usize = 5;
837+
let mut exact_memory = [0; EXACT_SIZE * node_size::<usize>()];
838+
storage.resize(&mut exact_memory);
839+
840+
// Verify relationships are still preserved
841+
let node0 = storage.get(0).unwrap();
842+
assert!(node0.left().is_some());
843+
assert!(node0.right().is_some());
844+
}
783845
}

0 commit comments

Comments
 (0)