Skip to content

Undefined Behavior in Vec::insert if passed an index outside of its capacity #122760

Closed
@jwong101

Description

@jwong101

I tried this code:

vec![].insert(usize::MAX, usize::MAX);

I expected to see this happen:
The program should panic, but not have any undefined behavior.

Instead, this happened:
Miri reports that the program triggers undefined behavior.

MIRI Backtrace

   Compiling playground v0.0.1 (/playground)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.51s
     Running `/playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/cargo-miri runner target/miri/x86_64-unknown-linux-gnu/debug/playground`
error: Undefined Behavior: out-of-bounds pointer arithmetic: alloc1582 has size 32, so pointer to 8 bytes starting at offset -8 is out-of-bounds
    --> /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/vec/mod.rs:1554:25
     |
1554 |                 let p = self.as_mut_ptr().add(index);
     |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: alloc1582 has size 32, so pointer to 8 bytes starting at offset -8 is out-of-bounds
     |
     = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
     = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
help: alloc1582 was allocated here:
    --> src/main.rs:2:5
     |
2    |     vec![].insert(usize::MAX, usize::MAX);
     |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
     = note: BACKTRACE (of the first span):
     = note: inside `std::vec::Vec::<usize>::insert` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/vec/mod.rs:1554:25: 1554:53
note: inside `main`
    --> src/main.rs:2:5
     |
2    |     vec![].insert(usize::MAX, usize::MAX);
     |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

error: aborting due to 1 previous error

Meta

It seems like the issue is here:

let p = self.as_mut_ptr().add(index);
if index < len {
// Shift everything over to make space. (Duplicating the
// `index`th element into two consecutive places.)
ptr::copy(p, p.add(1), len - index);
} else if index == len {
// No elements need shifting.
} else {
assert_failed(index, len);
}

The length check needs to happen before the computation of ptr::add, since it's undefined behavior if the new pointer is out of bounds of the allocation or overflows the address space.

rustc --version --verbose:

rustc 1.79.0-nightly (a7e4de13c 2024-03-19)

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessT-libsRelevant to the library team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions