replace_with
replace_with copied to clipboard
`replace_with[_and_return]` has undefined behavior if `default` panics.
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.
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.
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.