2

i am trying to read a value from pointer but i always get a double-free error. Do you guys know a way to fix it? I am using mem::forget to block the free operation but i still get the same result.

use std::ptr;
use std::mem;

fn main() {
    let test = String::from("hello!");
    println!("{}", get_value_from_ptr(&test));
    println!("{}", get_value_from_ptr(&test));
}

fn get_value_from_ptr<T>(val: &T) -> T {
    let value = unsafe { ptr::read(val) };
    mem::forget(&value);
    value
}

Error:

   Compiling playground v0.0.1 (/playground)
    Finished dev [unoptimized + debuginfo] target(s) in 1.26s
     Running `target/debug/playground`
free(): double free detected in tcache 2
timeout: the monitored command dumped core
/playground/tools/entrypoint.sh: line 11:     8 Aborted     
aiocat
  • 15
  • 1
  • 4

1 Answers1

1

mem::forget() must take an owned value. If you provide it with a reference, it'll forget the reference - which is meaningless since references do not have a Drop glue anyway. You'll have to mem::forget(value) and not mem::forget(&value), but then you move out of value and you cannot return it.

What you're trying to do is fundamentally impossible. You cannot duplicate a value soundly if it does not implement Copy. Even just ptr::read()ing it may invalidate the original value, even if you immediately forget() it (this is not decided yet). Using it after is a non-starter.

Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77
  • But i need to shallow-copy the value without cloning it. Does Rust have an "unsafe" way to do that? – aiocat Jun 08 '22 at 11:12
  • @aiocat Sorry to disappoint you, but this is fundamentally impossible: a type that can be bitwise duplicated is `Copy`. If a type does not implement that trait, then by definition it cannot be duplicated, at least without extra code (`Clone`). You may need to ask a new question with a more concrete use-case; maybe you're looking for `Rc`? – Chayim Friedman Jun 08 '22 at 11:13
  • No it is possible, but doing so is wildly unsafe. I would also recommend using `Rc` instead. You can improve the code in the question by using `ManuallyDrop` and making `get_value_from_ptr` unsafe. https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=b84fb9892e10c17a06d4e9cd5739145e – Locke Jun 08 '22 at 11:24
  • @Locke No, this is not possible, this is undefined behavior. You cannot duplicate a `String` bitwisely. `ManuallyDrop` is many times better than `mem::forget()` indeed, I didn't suggest it because the intent is impossible to achieve in this case anyway. – Chayim Friedman Jun 08 '22 at 11:25
  • is [this](https://gist.github.com/rust-play/60d8df6508ac5a7f72e3d834fb3a8004) a valid way to use `Rc`? – aiocat Jun 08 '22 at 11:33
  • @ChayimFriedman We have already established that the usage is undefined behavior, but this is by no means impossible. The question fundamentally boils down to perfectly copying and returning one piece of memory without modifying the original. With a little unsafe code this is easy for any sized type. Attempting to then use that copy for literally anything afterwards is the issue. I think that this is important since the type being copied might not be a string. For all we know, `String` may just be a placeholder for some complex `extern "C"` type. – Locke Jun 08 '22 at 11:34
  • @Locke thank you! it worked, but whats is the "downside" of using `ManuallyDrop` instead of `Rc`? like trying to read a null pointer? – aiocat Jun 08 '22 at 11:35
  • @aiocat Basically everything Chayim said. My answer is more just for completeness. Just use an `Rc`. – Locke Jun 08 '22 at 11:36
  • @aiocat The "only" downside is that you're doing thing that are completely unsound and may become UB tomorrow or yesterday. Don't do that. – Chayim Friedman Jun 08 '22 at 11:37
  • [Here's a simple example](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=b875242e3adcf3fc0cf61708e4a75f02) where usage of `ManuallyDrop` in your function can be turned into complete undefined behavior by all means that is even reported by Miri (and worse, happens to work). – Chayim Friedman Jun 08 '22 at 11:40
  • I am using `Rc` now. thanks for helping @ChayimFriedman & @Locke! – aiocat Jun 08 '22 at 11:45