Live data from Hacker News

No-Panic Rust: A Nice Technique for Systems Programming

blog.reverberate.org

101–110 of 143 posts

Re: No-Panic Rust: A Nice Technique for Systems Programming

#101
> fn check_invariant(&self) { > unsafe { assert_unchecked(self.ofs self.data.len()) } > }

Is fundamentally unsound `check_invariant` needs to be unsafe as it doesn't actually check the invariant but tells the compiler to blindly assume they hold. Should probably also be named `assume_invariant_holds()` instead of `check_invariant()`.

Re: No-Panic Rust: A Nice Technique for Systems Programming

#102
post #91

Earlier quoted context omitted.

After using rust for several years, I'm shocked this isn't the default. Making panics recoverable leads to them being used incorrectly.

Panics also unwind the stack and run all your Drop destructors. Setting `panic = abort` disables unwinding and this means leaking memory, not closing file descriptors, not unlocking mutexes and not rolling back database transactions on panic. It's fine for some applications to leave this to the operating system on process exit but I would argue that the default unwinding behavior is better for typical userspace appli…

All the things you describe are done automatically on program exit, even if the program is SIGKILL’ed. The kernel cleans up file descriptors, database transactions are rolled back automatically when the client disconnects (which it should be observed to be when the program exits and the kernel closes the connection as part of cleanup), and I’m not sure what you mean about mutexes, but if you mean in-memory ones, those don’t matter because the program is gone (if you mean like, file-based ones, those also should be implicitly unlocked by the kernel when the program exits, at least that’s how a good implementation is supposed to work, e.g. by writing the pid to the file or something.)

The whole of modern operating systems are already very familiar with the idea of programs not being able to exit gracefully, and there’s already a well understood category of things that happen automatically even if your program crashes ungracefully. Whole systems are designed around this (databases issuing rollbacks when the client disconnects, being a perfect example.) The best thing to do is embrace this and never, ever rely on a Drop trait being executed for correctness. Always assume you could be SIGKILLed at any time (which you always can. Someone can issue a kill -9, or you could get OOM killed, etc.)

Re: No-Panic Rust: A Nice Technique for Systems Programming

#103

> Unrecoverable panics are very much designed to be recoverable at some well defined boundaries (e.g. the request handler of a web server, a thread in a thread pool etc.) this is where most of it's overhead comes from you can use panic=abort setting to abort on panics and there is a funny (but unpractical) hack with which somewhat can make sure that no not-dead-code-eliminated code path can hit a panic (you link the…

I would say that you are using them incorrectly if you assume them as recoverable. You should make everything you can so that they never happen.

However, since it is still possible to have them in a place where the exiting the process is not okay, it was beneficial to add a way to recover from them. It does not mean that they are designed to be recoverable.

> this is where most of it's overhead comes from

Overhead comes from the cleaning process. If you don't clean properly, you might leak information or allocate more resources than you should.

Re: No-Panic Rust: A Nice Technique for Systems Programming

#104
post #91

Earlier quoted context omitted.

Panics also unwind the stack and run all your Drop destructors. Setting `panic = abort` disables unwinding and this means leaking memory, not closing file descriptors, not unlocking mutexes and not rolling back database transactions on panic. It's fine for some applications to leave this to the operating system on process exit but I would argue that the default unwinding behavior is better for typical userspace appli…

All the things you describe are done automatically on program exit, even if the program is SIGKILL’ed. The kernel cleans up file descriptors, database transactions are rolled back automatically when the client disconnects (which it should be observed to be when the program exits and the kernel closes the connection as part of cleanup), and I’m not sure what you mean about mutexes, but if you mean in-memory ones, thos…

I'm well aware of this and good that the option exists to bail out with abort instead.

But there are still cases where you would like to fsync your mmaps, print out a warning message or just make sure your #[should_panic] negative tests don't trigger false positives in your tooling (like leak detectors or GPU validators) or abort the whole test run.

It's not perfect by any means but it's better than potentially corrupting your data when a trivial assert fires or making negative tests spew warnings in ci runs.

It's very easy to opt out from, and I don't consider the price of panic handlers and unwinding very expensive for most use cases.

Re: No-Panic Rust: A Nice Technique for Systems Programming

#105
post #85

Earlier quoted context omitted.

As the author mentions, `panic!` is also not an acceptable failure mode in some applications. If you're developing safety-critical software and a process stopping is part of your risk analysis, many frameworks will ask you about the frequency of that happening. In that analysis, you may be required to set all systematic contributions to that frequency to zero. This happens, for example, if you try to control the asso…

Yes that condition I understand. But that seems orthogonal to the code size issue. Having no panics in code where the stdlib is riddled with panics for exceptional situations (allocation failure, for example) seems like a situation where you would just always go with no_std?

It is orthogonal, yes. To your question, I have an example from the same domain, where it is reasonable to mix unrolling panic with code that never panics.

Typically, safety-related processes are set up in two phases. First they set up, then they indicate readiness and perform their safe operation. A robot, for example, may have some process checking the position of the robot against a virtual fence. If the probability for passing through that fence passes some limit, this requires the process to engage breaks. The fence will need to be loaded from a configuration, communication with the position sensors will need to be established, the fence will generally need to be transformed into coordinates that can be guaranteed to be checked safely, taking momentum and today's breaking performance in account, for example. The breaks itself may need to be checked. All that is fine to do in an unsafe state with panics that don't just abort but unroll and full std. Then that process indicates readiness to the higher-level robot control process.

Once that readiness has been established, the software must be restricted to a much simpler set of functions. If libraries can guarantee that they won't call panic!, that's one item off our checklist that we can still use them in that state.

Re: No-Panic Rust: A Nice Technique for Systems Programming

#106
post #79

Earlier quoted context omitted.

> The fact that the program arrived there is a Logic error in your program. No, your program correctly determined that user input was invalid. Or your parser backtracked from parsing a Bool and decided to try to parse an Int instead.

That’s not invalid state. Your program correctly determined input is invalid. Say user input is a number and can never exceed 5. If the user input exceeds 5 your program should handle that gracefully. This is not invalid state. It is handling invalid input while remaining in valid state. Let say it does exceed 5 and You forget to check that it should never exceeds 5 and this leads to a division by zero further down y…

I know this is not your point for the last paragraph, but have you read about the C-130 complete navigation system failure while trying land below sea level at the Dead Sea? :)

https://news.ycombinator.com/item?id=14409950

Re: No-Panic Rust: A Nice Technique for Systems Programming

#108
post #103

> Unrecoverable panics are very much designed to be recoverable at some well defined boundaries (e.g. the request handler of a web server, a thread in a thread pool etc.) this is where most of it's overhead comes from you can use panic=abort setting to abort on panics and there is a funny (but unpractical) hack with which somewhat can make sure that no not-dead-code-eliminated code path can hit a panic (you link the…

I would say that you are using them incorrectly if you assume them as recoverable. You should make everything you can so that they never happen. However, since it is still possible to have them in a place where the exiting the process is not okay, it was beneficial to add a way to recover from them. It does not mean that they are designed to be recoverable. > this is where most of it's overhead comes from Overhead co…

> I would say that you are using them incorrectly if you assume them as recoverable.

no it's them being recoverable at well defined boundaries is a _fundamental_ design aspect of rust

> Overhead comes from the cleaning process. If you don't clean properly, you might leak information or allocate more resources than you should.

and that same cleanup process makes it recoverable

Re: No-Panic Rust: A Nice Technique for Systems Programming

#109
post #18
post #11

I've had an unpleasant amount of crashes with Rust software because people are way too quick to grab `panic!` as an out. This was most shocking to me in some of the Rust code Mozilla had integrated into Firefox (the CSS styling code). There was some font cache shenanigans that was causing their font loading to work only semi-consistently, and that would outright crash this subsystem, and tofu-ify CJK text entirely as…

At least sources of panic! are easily greppable. Cutting corners on error handling is usually pretty obvious

There are panics that aren't greppable that way. For instance `some_array[past_bounds]` causes a panic.

Re: No-Panic Rust: A Nice Technique for Systems Programming

#110
post #79

Earlier quoted context omitted.

> The fact that the program arrived there is a Logic error in your program. No, your program correctly determined that user input was invalid. Or your parser backtracked from parsing a Bool and decided to try to parse an Int instead.

That’s not invalid state. Your program correctly determined input is invalid. Say user input is a number and can never exceed 5. If the user input exceeds 5 your program should handle that gracefully. This is not invalid state. It is handling invalid input while remaining in valid state. Let say it does exceed 5 and You forget to check that it should never exceeds 5 and this leads to a division by zero further down y…

> You crash the program.

No thank you.

> Or you can put in a fail safe before the error bubbles up to main and do something else

In other words,

>> your parser backtracked from parsing a Bool and decided to try to parse an Int instead

> but now (if your program retains and mutates that state) has invalid values in it and a known bug as well.

Unless,

>>> The thing with functional programming (specifically, immutable data,) is that as long as the invalid state is immutable, you can just back up to some previous caller, and they can figure out whether to deal with it or whether to reject up the its previous caller.

Post reply on HN