Some things I learnt in the last few weeks

I think it's hard to do robustly, though that particular footgun may be removed through other means eventually. In the meanwhile, I believe that if you're going to drop any part of the payload you should use another catch_unwind! (or leak the payload). But doing this is rare. As it turns out, reasoning about panics is hard, even in code explicitly about catching panics, because of their often-invisible nature.

That said, you're also getting push-back because it's not idiomatic Rust and it's (excuse the pun) an exceptional code pattern, not an expected one. It is not what you should reach for as part of normal error handling, and it makes addressing the error cases invisible and forgettable -- anti-patterns in Rust.

So when an Rustacean reads "[As I Rust beginner I recently learned that panics] may be worth considering an an alternative to Result", they're probably going to jump in and correct you. Not just to be pedantic, but also to guide you toward idiomatic Rust and away from footguns.


More generally, this feels like one of those mid-level issues, like self-referential structures or falling back to raw pointers (or falling back to unsafe generally). Are they possible? Yes. Should you learn them and should we have better material about them? Eventually you should and we definitely could use some better or centralized material on some topics. Are they what you should be reaching for in your first projects and while you're still getting a feel for the language? Almost certainly not.

14 Likes

Yes, but I feel the beginners mistake I made was to use Result when Panic was a superior solution for my use case ( more readable code, less chance of coding mistakes ). I have a bad memory, so I am not sure what I believed originally, but I don't think I knew panics could be caught, or didn't consider that as a solution. My mistake!

1 Like

Before you get too confident about your apparently-uncommon skill at safely handling Panic, I suggest that you read the preprint of the just-announced on IRLO paper RUDRA: Finding Memory Safety Bugs in Rust at the Ecosystem Scale. Figure 3 in that paper is an example of a panic safety bug in String::retain() that RUDRA found in stable Rust's standard library.

Also see Table 4, "Details of the new bugs found in the 30 most popular packages on crates.io", which includes three more panic-handling safety bugs. As the rest of that table title states,

The RUDRA paper provides quite-convincing evidence that safely handling panics is extremely difficult, even for very experienced Rust programmers, including those who maintain rustc and std.

12 Likes

This is very interesting, thank you for reposting it here, I don't often go to IRLO.

2 Likes

Note that this bug relates to panic handling in the context of writing unsafe code—modifying the bytes of a str—which has many more pitfalls than panic handling in safe application code (which I assume is the context @geebee22 is operating in).

3 Likes

That is true. However, if the Rust ecosystem contains so many potentially-flawed responses when a panic does occur, then it might be wise to avoid that exposure by not deliberately inducing panics as a programming strategy. (Of course that exposure only occurs when one expects to recover from the panic.)

3 Likes

There is no special skill involved. It's necessary to make sure everything is in a consistent state before continuing (after reporting the error), ( "panic::AssertUnwindSafe" ) but that's not difficult in my situation. I am only writing in safe Rust, not venturing into truly dangerous waters!

1 Like

You can catch panics, but you can't assume your panics can be caught, especially if you're writing libraries. Danger of double panics are already mentioned, and it's not that rare people compile their binaries in panic = "abort" mode, which abort the process immediately after the panic without stack unwinding.

3 Likes

Note: The same author posted a separate thread all about panic and catch_unwind. Some of this commentary might fit better in that thread, or has already been covered there.

1 Like

:neutral_face: I don’t know very well, can you provide a more detailed sample code description? Thank you.

Some more information and examples about T: 'static vs &'static T can be found in

rust-blog/common-rust-lifetime-misconceptions.md at master ¡ pretzelhammer/rust-blog ¡ GitHub

in particular in sections 2) and 3)

1 Like

I see this thread got some traction over panics.

I'd like to add to your list std::mem::take() which, given a type that implements default replaces mut ref with default and gives you the referenced value. Much like Option::take(). I use that a lot in situations with async Sync and Send implementations. Not sure if this is in the book :slight_smile:

I'm also fond of async traits and figured I don't really need to depend on async-trait crate for that (and the bunch of proc macro deps). This is my typical use case. On top of async-trait, it allows me to achieve a Sync future, or do some preparation before the async code. It is a bit verbose, but with a bit of practice it actually helps one really understand and get the knack for lifetimes.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.