]> git.lizzy.rs Git - rust.git/commitdiff
Don't do pointer arithmetic on pointers to deallocated memory
authorThe 8472 <git@infinite-source.de>
Mon, 16 Jan 2023 20:39:36 +0000 (21:39 +0100)
committerThe 8472 <git@infinite-source.de>
Tue, 17 Jan 2023 21:01:33 +0000 (22:01 +0100)
vec::Splice can invalidate the slice::Iter inside vec::Drain.
So we replace them with dangling pointers which, unlike ones to
deallocated memory, are allowed.

library/alloc/src/vec/drain.rs
library/alloc/src/vec/splice.rs

index 541f99bcfaba4582ad801dc81de5075c5830aed3..2b1a787cc549929231be0dfe33f1b8b57d1e9441 100644 (file)
@@ -223,9 +223,9 @@ fn drop(&mut self) {
         }
 
         // as_slice() must only be called when iter.len() is > 0 because
-        // vec::Splice modifies vec::Drain fields and may grow the vec which would invalidate
-        // the iterator's internal pointers. Creating a reference to deallocated memory
-        // is invalid even when it is zero-length
+        // it also gets touched by vec::Splice which may turn it into a dangling pointer
+        // which would make it and the vec pointer point to different allocations which would
+        // lead to invalid pointer arithmetic below.
         let drop_ptr = iter.as_slice().as_ptr();
 
         unsafe {
index bad765c7f51fab944b3de89a3a956de2dd42f158..1861147fe72fb676920d5a8ac8847288253e6797 100644 (file)
@@ -54,6 +54,12 @@ impl<I: Iterator, A: Allocator> ExactSizeIterator for Splice<'_, I, A> {}
 impl<I: Iterator, A: Allocator> Drop for Splice<'_, I, A> {
     fn drop(&mut self) {
         self.drain.by_ref().for_each(drop);
+        // At this point draining is done and the only remaining tasks are splicing
+        // and moving things into the final place.
+        // Which means we can replace the slice::Iter with pointers that won't point to deallocated
+        // memory, so that Drain::drop is still allowed to call iter.len(), otherwise it would break
+        // the ptr.sub_ptr contract.
+        self.drain.iter = (&[]).iter();
 
         unsafe {
             if self.drain.tail_len == 0 {