Is there any plan to remove panics from std?

Currently, println!() panics - which is neither obvious, nor strictly necessary.

Dealing with out-of-memory issues isn't particularly feasible either, which might be hurting the whole language and the community around it in terms of adoption.

Is there any plan to reduce these down to zero with Option / Result?

Or do we only care about safety when it comes to higher-level abstractions?

2 Likes

OOM is a separate problem. It currently forces process abort instead of unwind-panicking, but there's a plan to have oom=panic option.

I don't think there are any plans to remove panic from std. panic is technically safe by Rust's definition of safety, even though requires extra care when mixed with unsafe. Personally I'd like to see better tooling for detecting and forbidding panics, like a built-in #[no_panic].

You can use write!(std::io::stdout())? to handle failures. println! is designed for convenience. It can't be changed to return an error, and I'm not sure if a silent failure is better than a panic.

18 Likes

Maybe println! specifically could silently fail, but there is no (backwards compatible) way to remove panics from std. Consider Index, args(), and many others.

4 Likes

I could have phrased the question better: obviously, it would be downright harmful to remove the panic! itself from the standard library - if a hard drive or the RAM of the PC fails, there's nothing you can do, so the only reasonable option is to launch the unwinding process.

But in case of the OOM issues, if the process gets simply aborted we have a bigger kind of issue. What kind of 'memory-safe' language would stop the whole program if there aren't enough MBs to allocate a new struct for? After discovering the post of Linus, honestly, I feel a bit deceived by the biggest Rust promise of all - either the language is safe and sound in its entirety, or it's only safe when it's convenient. There's nothing safe about shutting down the process on a failed allocation.

As for the println!() - I think, at the very least, the safer alternatives can be mentioned to those who might be interested in them in the docs. The Rust book doesn't mention the fact that your program can crash if the stdout isn't readily accessible, that's for sure. And a silent failure would be a bit more appropriate, IMO. We're just printing a message, not trying to access an invalid memory location.

3 Likes

Rust doesn't promise programs to be bug-free. Rust's safety is about memory and thread safety. Aborting process on OOM is safe from this limited perspective.

Rust has focus on reliability, and I agree that the current pessimistic OOM handling is poor. There are plans to fix that. Fixing that doesn't depend on removal of panic!. OOM and panicking are two orthogonal issues (please don't confuse Rust's unwind-panic with Linux kernel panic.)

Note that there's also panic=abort option which turns all panics into aborts. That is also safe, since the process aborts before an unrecoverable condition could do any damage.

17 Likes

No one can promise that, obviously - but we've got to take care of what can be solved.

That's all I wanted to hear.

1 Like

Fallible allocation is an accepted RFC and will land eventually.

Never aborting nor panicking is not Rust's definition of safe. There are no data races, use after free, etc. that result from aborting on OOM.

Shutting down the process upon failed allocation is certainly more (memory) safe than silently handing back an invalid reference/pointer/struct/whatever that causes undefined behavior. Given the infallible signature of Vec::push, say, what other reasonable alternative is there?

9 Likes

Awesome.

Perhaps a fallible alternative should be added there as well?

In the short term there's try_reserve landing. In the longer term there's:

and for Linux kernel specifically, the solution is to avoid Rust's standard library completely. Aborting is not part of the language, only implementation detail of a bundled alloc crate, which is technically optional.

Fallible allocation has been slow to come, because there's a lot of bikeshedding around it (people keep proposing and rejecting the same things for the same reasons, over and over again). Some participants in these conversations don't even believe that programs should even try or could handle OOM at all, which is why we've got the aborting behavior in the first place.

8 Likes

Yes, I imagine so.

It's hard not to notice, with them being around since 2017 and '18.

That's a weird credo to have, given the promises of the language and its priorities, honestly.

Honestly, it's not. For several reasons.

First is that dealing with allocation failures is a niche concern. That doesn't mean it's unimportant, but it's niche. I've been writing Rust for a long time and I've never wanted anything other than "abort on OOM" semantics. There's a whole world out there for which the current behavior in std is just fine.

Second is that aborting on allocation failure is a property of the standard library, not the language. This is why Linux kernel development is able to use Rust: they don't have to use the alloc crate. They can build their own. That's what they're doing.

Third is that in many common scenarios (such as on many Linux distros), overcommit is enabled. This means that you're unlikely to ever even get an allocation failure. Instead, your process just aborts at the time of a memory write and there is likely nothing you can (or will) do about it unless you change your overcommit settings.

Plenty of old and existing systems tooling (like, for example, grep) will just abort when it can't allocate memory. I don't recall ever hearing anyone complain about that kind of behavior. There are for sure certain scenarios in said tooling where detecting allocation failure is a useful technique, but it's not the norm. And that's one of the reasons why folks are working on bringing fallible APIs to std.

You might consider that others have different definitions of what "memory-safe" means. Aborting on a failed allocation is not something that Rust (nor anyone I know) considers memory unsafe.

No, there is no plan to change this because the only choice for removing the panic is a silent failure, and I (as a member of the libs-api team) would consider that a pretty serious breaking change. (For example, it would turn programs today that abort when the stdout pipe is closed into programs that might never abort.) And the panicking behavior of println! is documented. If we could do it over, I might advocate for something different, but that ship has sailed IMO.

28 Likes

I would add that print! and println! are convenience macros. They're great for quick 'n dirty printing but not necessarily what you want in many types of applications (e.g. I think they constantly lock/unlock stdout). On the other hand write! and writeln! are better in many cases because they can be adapted to suite a range of needs. They are but a thin wrapper around a write_fmt function and can indeed return a Result (or anything else).

8 Likes

As much as I like to write pedantically correct software, I don’t believe it is possible outside of safety critical systems. One good example here is stack space usage: as a writer of user-space program, you don’t really have a way to ensure that you never overflow the stack. As soon as you call into libc, you just hope that whatever amount of stack you have would be enough.

26 Likes