RFC 2116 addresses part of the issue. The other part of the problem would be to support disabling the non-fallible APIs at compile time.
Also, RFC 2116 assumes that it's sufficient to provide (for instance) Vec::try_reserve, and require callers to always call that before calling anything that might expand the Vec. That wouldn't eliminate the runtime panics. It might be necessary to go a step further, and actually provide fallible versions of individual Vec methods. (Or there may be other potential solutions.)
Yeah `try_reserve` is ~~racy and~~ (edit, strikethrough) awkward to use. And having a bunch of a panics which "should" be dead code because of the proceeding `try_reserve` at best adds a bunch of noise burdening static analysis.
A bunch of us, anticipating a reaction like Linus' have been arguing that we need `try_` versions of everything and* a way to prevent the other ones from being used. (Cargo features?) I sincerely hope we finally get that.
> A bunch of us, anticipating a reaction like Linus' have been arguing that we need `try_` versions of everything and* a way to prevent the other ones from being used.
This has been anticipated since panic on OOM was introduced.
Adding `try_` version of everything is a horrible solution.
What you want is for the normal APIs to return Result<R,E> where E=! when panic on OOM and some OOM error otherwise.
The largest irony of all time is that, while returning an error on OOM works well on Windows, it makes little sense on Linux because overcommit is often enable by default. Linux and Linux users are directly responsible for the "panic on OOM" that turns out now prevents liballoc from being used in the Linux kernel.
The obvious fix here is for the kernel to use overcommit internally \s
But it's still non-local. one has to manually account for what allocation will be done, and keep the reservation in sync across refactors. This isn't a race but still scares me.
which would be a race. That is not `try_reserved`'s fault, and a rather easy-to-spot example, but I wonder if there are variations on this which are easier to miss.
They probably meant it is a race, not racy. Although, it's not a race I think? The method will attempt to reserve, or return Err, just like malloc would (it's not can_reserve)
let v = vec![0; 42];
v.try_reserve(1);
frob(&mut v); // I expect this not to expand the array
v.push(1); // fails, because frob took the space
Note that this requires passing a mutable reference to frob. Absent an explicit contract in the api documentation I wouldn't expect a function that takes a mutable reference to a vec not to mutate it arbitrarily.
One option for avoiding this would be to pass a mutable reference to a slice, which allows frob to mutate elements of the vec without allowing it to push.
frob(&v[..])
It can't be a race in the traditional sense, as the borrow checker will enforce only one person being able to write at a time.
Also, RFC 2116 assumes that it's sufficient to provide (for instance) Vec::try_reserve, and require callers to always call that before calling anything that might expand the Vec. That wouldn't eliminate the runtime panics. It might be necessary to go a step further, and actually provide fallible versions of individual Vec methods. (Or there may be other potential solutions.)