由于我今天发现了这个代码库中的不安全之处(参见 #1485 ),我决定仔细检查一下。
我发现 RefMutContainer
会擦除生命周期,从而导致更不安全的代码。
源代码位置:
tokenizers/bindings/python/src/utils/mod.rs
第44行到第66行 in 14a07b0
| | #[derive(Clone)] |
| | pubstructRefMutContainer{ |
| | inner:Arc<Mutex<Option<*mutT>>>, |
| | } |
| | implRefMutContainer{ |
| | pubfnnew(content:&mutT) -> Self{ |
| | Self{ |
| | inner:Arc::new(Mutex::new(Some(content))), |
| | } |
| | } |
| | |
| | pubfnmap<F:FnOnce(&T) -> U,U>(&self,f:F) -> Option{ |
| | let lock = self.inner.lock().unwrap(); |
| | let ptr = lock.as_ref()?; |
| | Some(f(unsafe{ ptr.as_ref().unwrap()})) |
| | } |
| | |
| | pubfnmap_mut<F:FnOnce(&mutT) -> U,U>(&mutself,f:F) -> Option{ |
| | let lock = self.inner.lock().unwrap(); |
| | let ptr = lock.as_ref()?; |
| | Some(f(unsafe{ ptr.as_mut().unwrap()})) |
| | } |
| | } |
注意,我没有检查这里是否真的存在不安全之处。然而,由于这里的安全性无法在本地保证,这些方法至少应该被标记为 unsafe
,但更好的做法是修复它们以使其正确。
下面是一个示例代码,当使用 Miri 检查时会显示未定义的行为:
let container = {
let mut content = String::from("foo");
RefMutContainer::new(&mut content)
};
container.map(|text| {
// Triggers UB
println!("{text}");
});
链接到Playground:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=fede2ac43a1fdb8b5e499b505e9ecdea
Miri产生的错误:
error: Undefined Behavior: out-of-bounds pointer use: alloc1256 has been freed, so this pointer is dangling
--> /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/slice/raw.rs:138:9
|
138 | &*ptr::slice_from_raw_parts(data, len)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: alloc1256 has been freed, so this pointer is dangling
|
= 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: alloc1256 was allocated here:
--> src/main.rs:29:20
|
29 | let mut text = String::from("foo");
| ^^^^^^^^^^^^^^^^^^^
help: alloc1256 was deallocated here:
--> src/main.rs:31:5
|
31 | drop(text);
| ^^^^^^^^^^
= note: BACKTRACE (of the first span):
= note: inside `std::slice::from_raw_parts::<'_, u8>` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/slice/raw.rs:138:9: 138:47
= note: inside `<std::vec::Vec<u8> as std::ops::Deref>::deref` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/vec/mod.rs:2831:18: 2831:64
= note: inside `<std::string::String as std::ops::Deref>::deref` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/string.rs:2487:43: 2487:52
= note: inside `<std::string::String as std::fmt::Display>::fmt` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/string.rs:2376:28: 2376:34
= note: inside `<&std::string::String as std::fmt::Display>::fmt` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/fmt/mod.rs:2377:62: 2377:82
= note: inside `core::fmt::rt::Argument::<'_>::fmt` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/fmt/rt.rs:173:76: 173:95
= note: inside `std::fmt::write` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/fmt/mod.rs:1178:21: 1178:44
= note: inside `<std::io::StdoutLock<'_> as std::io::Write>::write_fmt` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/io/mod.rs:1823:15: 1823:43
= note: inside `<&std::io::Stdout as std::io::Write>::write_fmt` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/io/stdio.rs:786:9: 786:36
= note: inside `<std::io::Stdout as std::io::Write>::write_fmt` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/io/stdio.rs:760:9: 760:33
= note: inside `std::io::stdio::print_to::<std::io::Stdout>` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/io/stdio.rs:1116:21: 1116:47
= note: inside `std::io::_print` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/io/stdio.rs:1226:5: 1226:37
note: inside closure
--> src/main.rs:35:7
|
35 | println!("{text}");
| ^^^^^^^^^^^^^^^^^^
note: inside `RefMutContainer::<std::string::String>::map::<{closure@src/main.rs:33:19: 33:25}, ()>`
--> src/main.rs:18:14
|
18 | Some(f(unsafe { ptr.as_ref().unwrap() }))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `main`
--> src/main.rs:33:5
|
33 | / container.map(|text| {
34 | | // Triggers UB
35 | | println!("{text}");
36 | | });
| |______^
= note: this error originates in the macro `println` (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
3条答案
按热度按时间xhv8bpkk1#
Similar reproduction as above, but just showing that it can easily be even more innocent than an explicit
drop
a8jjtwal2#
类似于上面的复制,但只是表明它可以轻松地甚至比一个明确的
drop
哈哈,竞争条件!
我只是用你的建议更新了它 :)
db2dz4w83#
仔细观察这个,我想不出任何情况下这不是
这个结构体应该要么
&mut T
而不是一个*mut T