Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions crates/inplace-vec-builder/RUSTSEC-0000-0000.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
```toml
[advisory]
id = "RUSTSEC-0000-0000"
package = "inplace-vec-builder"
date = "2026-03-09"
url = "https://github.com/rklaehn/inplace-vec-builder/issues/1"
informational = "unsound"
categories = ["memory-corruption"]
keywords = ["soundness", "double-free", "mem-forget", "set-len"]

[versions]
patched = []
unaffected = []
```

# `InPlaceVecBuilder` can be leaked to corrupt the backing `Vec`

`InPlaceVecBuilder` temporarily moves elements inside the backing `Vec` and
sets the vector length to its capacity while building the target region. Its
safety relies on the builder's `Drop` implementation restoring the correct
length and cleaning up the intermediate state.

Because `std::mem::forget` is safe, callers can leak the builder after a method
such as `push` has entered this intermediate state. This bypasses the `Drop`
cleanup and exposes the backing `Vec` with an invalid length and duplicated or
otherwise invalid elements. Subsequent safe use or drop of the `Vec` can trigger
undefined behavior, including double free and use-after-free.

No patched version is currently available. The issue affects the published
versions `0.1.0` and `0.1.1`.

## Example

```rust
use inplace_vec_builder::InPlaceVecBuilder;

fn main() {
let mut vec = vec![String::from("A"), String::from("B")];

{
let mut builder = InPlaceVecBuilder::from(&mut vec);
builder.push(String::from("X"));
std::mem::forget(builder);
}

println!("Corrupted Vec length is now: {}", vec.len());
}
```

## Miri output

Miri reports undefined behavior when the corrupted vector is later dropped:

```text
Corrupted Vec length is now: 4
error: Undefined Behavior: pointer not dereferenceable: alloc396 has been freed, so this pointer is dangling
--> library/core/src/ptr/mod.rs:805:1
|
805 | pub const unsafe fn drop_in_place<T: PointeeSized>(to_drop: *mut T)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior

help: alloc396 was allocated here:
--> src/main.rs:145:43
|
145 | let mut vec = vec![String::from("A"), String::from("B")];
| ^^^^^^^^^^^^^^^^^

help: alloc396 was deallocated here:
--> src/main.rs:161:1
|
161 | }
| ^
```