replace_with icon indicating copy to clipboard operation
replace_with copied to clipboard

`replace_with[_and_return]` has undefined behavior if `default` panics.

Open Mokuzzai opened this issue 1 year ago • 1 comments

The two functions:

Both have undefined behavior, since they can cause a double use if the default closure provided panics.

While the documentation says that default should not panic, because they are both safe functions default panicing must not cause undefined behavior.

An important note

On panic (or to be more precise, unwinding) of the closure f, default will be called to provide a replacement value. default should not panic – doing so will constitute a double panic and will most likely abort the process.

Panicing while unwinding may cause the process to abort, but you cannot rely on it for soundness, so the following example has ub.

let mut string = String::new();

replace_with(
    &mut string, 
    || panic!(),  // if this panic doesn't cause abort `string` will be freed twice
    |s| { 
        drop(s); // `s´ dropped here
        
        panic!()
    }
);

drop(string); // use after free

The solution is to check if default panics and abort the process.

Mokuzzai avatar Apr 30 '23 19:04 Mokuzzai

Panicing while unwinding may cause the process to abort, but you cannot rely on it for soundness

Huh, thanks for raising this! For reference, the best (and only) docs I could find confirming this:

https://github.com/rust-lang/rust/blob/f2eb9f85b9b52e6538c3c7fc160725963272d471/library/std/src/panicking.rs#L701-L704

Feel free to PR a fix, else I can in a couple weeks' time.

alecmocatta avatar Apr 30 '23 20:04 alecmocatta