Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pointer dereferenced after allocation was freed in String::replace_range #2759

Closed
Erutuon opened this issue Jan 16, 2023 · 1 comment · Fixed by rust-lang/rust#106950
Closed

Comments

@Erutuon
Copy link

Erutuon commented Jan 16, 2023

Miri reported a pointer being dereferenced after its allocation was freed in a function using String::replace_range in a test (ip::sanitize_ip_recognizes_subpages_of_ipv6_address) in the mwtitle library, and this was reported in Wikimedia Phabricator by @legoktm.

I couldn't detect an error in the code, and the test runs fine in stable and nightly, but I reduced the Miri-error-producing code to this minimal example:

fn main() {
    let mut input = "1".to_string();
    input.replace_range(0..0, "0");
}

If I reduce the input "1" or the replacement "0" to a zero-length string, or if I change the range to 0.. or .., there is no error.

The code looks correct and it compiles and runs fine in nightly. I thought this might be a Rustc problem generating code that's incorrect (freeing an allocation early) but happens not to crash so is only caught by Miri, but I'm not very familiar with how Miri works, so I thought I'd post here first.

The full error from `cargo +nightly miri run`

Preparing a sysroot for Miri (target: x86_64-unknown-linux-gnu)... done
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `~/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/cargo-miri runner target/miri/x86_64-unknown-linux-gnu/debug/miri-mwtitle`
error: Undefined Behavior: pointer to alloc1704 was dereferenced after this allocation got freed
   --> ~/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/slice/iter.rs:127:1
    |
127 | / iterator! {struct Iter -> *const T, &'a T, const, {/* no mut */}, {
128 | |     fn is_sorted_by(self, mut compare: F) -> bool
129 | |     where
130 | |         Self: Sized,
...   |
136 | |     }
137 | | }}
    | |__^ pointer to alloc1704 was dereferenced after this allocation got freed
    |
    = 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
    = note: BACKTRACE:
    = note: inside ` as std::iter::ExactSizeIterator>::len` at ~/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/slice/iter/macros.rs:25:22: 25:55
    = note: inside ` as std::ops::Drop>::drop` at ~/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/vec/drain.rs:201:24: 201:34
    = note: inside `std::ptr::drop_in_place::> - shim(Some(std::vec::Drain<'_, u8>))` at ~/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:490:1: 490:56
    = note: inside `std::ptr::drop_in_place::>> - shim(Some(std::vec::Splice<'_, std::str::Bytes<'_>>))` at ~/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:490:1: 490:56
    = note: inside `std::string::String::replace_range::>` at ~/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/string.rs:1826:80: 1826:81
note: inside `main`
   --> src/main.rs:3:5
    |
3   |     input.replace_range(0..0, "0");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: this error originates in the macro `len` which comes from the expansion of the macro `iterator` (in Nightly builds, run with -Z macro-backtrace for more info)

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

error: aborting due to previous error

Versions

Probably doesn't matter, but I ran this in Ubuntu in WSL.

rustc +nightly --version --verbose && echo && cargo +nightly miri --version:

rustc 1.68.0-nightly (9e75dddf6 2023-01-15)
binary: rustc
commit-hash: 9e75dddf609c0201d03f9792e850f95d6a283d11
commit-date: 2023-01-15
host: x86_64-unknown-linux-gnu
release: 1.68.0-nightly
LLVM version: 15.0.6

miri 0.1.0 (9e75ddd 2023-01-15)
@saethlin
Copy link
Member

Miri is correctly identifying a bug in the standard library, here's a candidate fix: rust-lang/rust#106950

compiler-errors added a commit to compiler-errors/rust that referenced this issue Jan 18, 2023
Don't do pointer arithmetic on pointers to deallocated memory

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.

Fixes miri test failures.
Fixes rust-lang/miri#2759
bors pushed a commit that referenced this issue Jan 23, 2023
Don't do pointer arithmetic on pointers to deallocated memory

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.

Fixes miri test failures.
Fixes #2759
thomcc pushed a commit to tcdi/postgrestd that referenced this issue May 31, 2023
Don't do pointer arithmetic on pointers to deallocated memory

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.

Fixes miri test failures.
Fixes rust-lang/miri#2759
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants