Live data from Hacker News

No-Panic Rust: A Nice Technique for Systems Programming

blog.reverberate.org

61–70 of 143 posts

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

#61
post #6
post #2

This website makes by browser freeze... No idea why. Not able to read the article.

Author here -- that is surprising. What browser/OS are you on? I haven't had anyone else report this problem before.

same for me. Chrome on Pixel 8

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

#62
post #39

Earlier quoted context omitted.

This isn't quite the same, but it reminds me of something a bit less clever (and a lot less powerful) I came up with a little while back when writing some code to handle a binary format that used a lot of 32-bit integers that I needed to use for math on indexes in vectors. I was fairly confident that the code would never need to run on 16-bit platforms, but converting from a 32-bit integer to a usize in Rust technica…

What about just doing something like #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] #[inline(always)] const fn usize_to_u32(x: usize) -> u32 { x as u32 } and this way you can just call this function and you'll get a compile-time error (no such function) if you're on a 16-bit platform.

Even though I can visually verify that it's safe in this context, I really don't like casting integers as a rule when there's a reasonable alternative. The solution I came up with is pretty much equally readable in my opinion but has the distinction of not having code that might in other contexts look like it could silently have issues (compared to an `unreachable!()` macro which might also look sketchy but certainly wouldn't be quiet if it accidentally was used in the wrong spot). I also prefer having a compiler error explaining the invariant that's expected rather than a missing function (which could just as easily be due to a typo or something). You could put a `compile_error!()` invocation to conditionally compile when the pointer width isn't at least 32, but I'd argue that tilts the balance even more in favor of the solution I came up with; having a single item instead of two defined is more readable in my opinion.

This wasn't a concern for me but I could also imagine some sort of linting being used to ensure that potentially lossy casts aren't done, and while it presumably could be manually suppressed, that also would just add to the noisiness.

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

#63

Earlier quoted context omitted.

There is panic-analyzer [1] that searches for code that needlessly panics. You can also use the no-panic macro [2] to turn possible panics in a specific function (including main) into a compile error 1: https://crates.io/crates/panic-analyzer 2: https://crates.io/crates/no-panic

Panic-analyzer looks like it is based on heuristics, searching for known-panicing APIs. I tried it on a workspace that uses io::stdout() and it did not flag this as potentially panicing. No-panic looks nifty: it appears to be reliable, which is great. I wish there was an easy way to automatically apply this annotation to every single function in a given file or crate.

I think the article is wrong in that std::io::stdout would be panicking, or that "the panic is reachable somehow". It's just the optimizer doesn't see it doesn't panic.

https://doc.rust-lang.org/beta/src/std/io/stdio.rs.html#674-...

The implementation calls indeed a panicking API, OnceLock::get_or_init:

https://doc.rust-lang.org/beta/std/sync/struct.OnceLock.html...

But it only panicks if it is being used in a wrong way, which it isn't. The usage is contained within the implementation of std::io::stdout, so it's an implementation detail.

It's a shame that there are no better ways to eliminate panics in case they are impossible to trigger. The article shows some tricks, but I think the language is missing still some expressability around this, and the stdlib should also thrive harder to actually get rid of hard-to-optimize links to panic runtime in case of APIs that don't actually panic.

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

#64

The approach at the end of declaring invariants to the compiler so the compiler can eliminate panics seems accidentally genius. You can now add the same invariants as panicking asserts at the end of each function, and the compiler will prove to you that your functions are upholding the invariants. And of course you can add more panicking asserts to show other claims to be true, all tested at compile time. You've basi…

>and the compiler will prove to you that your functions are upholding the invariants

From the article and only vague background Rust knowledge, I'm under the impression that the opposite is true: the compiler does not prove that. Hence why it's "assert_unchecked" - you are informing the compiler that you know more than it does.

You do get panics during debug, which is great for checking your assumptions, but that relies on you having adequate tests.

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

#65
post #35

Earlier quoted context omitted.

Sometimes the program is in an invalid state. You don't want to keep running the program. Better to fail spectacularly and clearly then to fail silently and try to hobble along.

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. This is why Result (or Maybe, or runExceptT, and so on in other languages) is a perfectly safe way of handling unexpected or invalid data. As long as you en…

The program can detect invalid state, but your intention was to never get to that state in the first place. The fact that the program arrived there is a Logic error in your program. No amount of runtime shenanigans can repair it because the error exists without your knowledge of where it came from. You just know it's invalid state and you made a mistake in your code.

The best way to handle this is to crash the program. If you need constant uptime, then restart the program. If you absolutely need to keep things running then, yeah try to recover then. The last option isn't as bad for something like an http server where one request caused it to error and you just handle that error and keep the other threads running.

But for something like a 3D video game. If you arrive at erroneous state, man. Don't try to keep that thing going. Kill it now.

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

#66
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…

Sometimes the program is in an invalid state. You don't want to keep running the program. Better to fail spectacularly and clearly then to fail silently and try to hobble along.

I understand this belief abstractly. In the cases I was hitting, there would have been easy recovery mechanisms possible (that would have been wanted because there are many ways for the system to hit the error!), but due to the lowest level "key lookup" step just blowing up rather than Result (or Option)-ing their lookup, not only would the patch have been messy, but it would have required me to make many decisions in "unrelated" code in the meanwhile.

I understand your point in general, I just find that if you're writing a program that is running on unconstrained environments, not panic'ing (or at least not doing it so bluntly at a low level) can at the very least help with debugging.

At least have the courtesy to put the panic at a higher level to provide context beyond "key not found!"!

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

#67
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

It is interesting to consider how `panic!` serves as some documentation of explicitly giving up. Easy to see in a pull request. And having the string packed alongside it is nice.

Still miffed, but we'll get there.

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

#68
post #48
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…

While sure, more things could be baked as results, most of the time when you see a panic that's not the case. It's a violation of the callee's invariants that the caller fucked up. Essentially an error means that the caller failed in a way that's expected. A panic means the caller broke some contract that wasn't expressed in the arguments. A good example of this is array indexing. If you're using it you're saying tha…

I understand the value of panic when your invariants really are no longer holding. What I have seen is many cases of "oh a micro-invariant I kind of half believe to be true isn't being held, and so I will panic".

Obviously context-free this is very hand wave-y, but would you want Firefox to crash every time a website prematurely closes its connection to your browser for whatever reason? No, right? You would want Firefox to fail gracefully. That is what I wanted.

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

#69
post #42

This seems to obviate a lot of Rust's advantages (like a good std library). I wonder what it would take to write a nopanic-std library? Panics really seem bad for composability. And relying on the optimzer here seems like a fragile approach. (And how is there no -nopanic compiler flag?)

Rust doesn't want to add any proof-system that isn't 100% repeatable, reliable, and forwards compatible to the language. The borrow checker is ok, because it meets those requirements. The optimizer based "no panic" proof system is not. It will break between releases as LLVM optimizations change, and there's no way to avoid it. Trying to enforce no-panics without a proof system helping out is just not a very practical…

To add to this, I believe that there will always be some amount of "should never happen but I can't prove it" due to Rice's Theorem[1].

[1]: https://en.wikipedia.org/wiki/Rice%27s_theorem

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

#70
post #66

Earlier quoted context omitted.

Sometimes the program is in an invalid state. You don't want to keep running the program. Better to fail spectacularly and clearly then to fail silently and try to hobble along.

I understand this belief abstractly. In the cases I was hitting, there would have been easy recovery mechanisms possible (that would have been wanted because there are many ways for the system to hit the error!), but due to the lowest level "key lookup" step just blowing up rather than Result (or Option)-ing their lookup, not only would the patch have been messy, but it would have required me to make many decisions i…

Without knowing the exact situation, if you follow the guidelines in this article, this is a library bug (documentation or actual code).

Either the library should have enforced the invariant of the key existing (and returned an equivalent error, or handled it internally), or documented the preconditions at a higher level function that you could see.

Post reply on HN