Discussion
Loading...

Discussion

  • About
  • Code of conduct
  • Privacy
  • Users
  • Instances
  • About Bonfire
Taggart
@mttaggart@infosec.exchange  ·  activity timestamp 2 days ago

Buried in this nicely-detailed RCA is a pretty damning fact:

Cloudflare left .unwrap() in mission-critical Rust code.

For non-Rustaceans, .unwrap() handles a type called Result that can either be Ok with a value, or an Err with an Error. The whole point is to gracefully handle errors and not let panics make it to production code. But unwrap() assumes there's a value to extract without safeguards.

I use .unwrap() sometimes! Usually when there's a logical guarantee that the result can never be an error. But I make sure to purge it from critical processes for exactly this reason.

https://blog.cloudflare.com/18-november-2025-outage/

Rust code using .unwrap() at the end of a function call chain
Rust code using .unwrap() at the end of a function call chain
Rust code using .unwrap() at the end of a function call chain
  • Copy link
  • Flag this post
  • Block
yaleman
@yaleman@mastodon.social replied  ·  activity timestamp yesterday

@mttaggart it really was the laziest of lazy, they're literally in a function with an error return option and yolo'ing it with unwrap was sad to see. This is why the clippy lints denying usage of it (and expect) in production code are mandatory in my eyes.

Also https://nounwrap.yaleman.org for why I think unwrap should be removed and leave expect for when you really want to panic your code 😃

  • Copy link
  • Flag this comment
  • Block
Taggart
@mttaggart@infosec.exchange replied  ·  activity timestamp yesterday

@yaleman Ehh, I think both have their place. I sometimes really want the traceback from unwrap() more than the business logic.

  • Copy link
  • Flag this comment
  • Block
Hartmut Seichter
@retrakker@mastodon.social replied  ·  activity timestamp yesterday

@mttaggart love #rust, but as with any programming language there is always an obvious and insanely practical way to shoot yourself in the foot or head or both.

  • Copy link
  • Flag this comment
  • Block
Jippi 🇩🇰
@jippi@expressional.social replied  ·  activity timestamp yesterday

@mttaggart think its kinda stretching it to say it was "Buried" - it was highlighted and explained what it did and that it was the issue

  • Copy link
  • Flag this comment
  • Block
Flounder
@fl0und3r@defcon.social replied  ·  activity timestamp yesterday

@mttaggart I feel like all programming languages toe the line between being too permissive and everything breaks or too conservative and nobody uses it. For what it's worth I think rust does a good job striking this balance.

this is cloudflares fault and I really hope no one focuses their "this must never happen again" energy at Rust.

  • Copy link
  • Flag this comment
  • Block
EndlessMason
@EndlessMason@hachyderm.io replied  ·  activity timestamp yesterday

@mttaggart
Isn't crashing the right choice when your rules enforcement engine can't fit all the rules into memory?

  • Copy link
  • Flag this comment
  • Block
Matt Palmer
@womble@infosec.exchange replied  ·  activity timestamp 2 days ago

@mttaggart oh dear. Unwrap should only be used at Christmas.

  • Copy link
  • Flag this comment
  • Block
lnicola
@lnicola@mapstodon.space replied  ·  activity timestamp 2 days ago

@mttaggart Do you use `assert!`?

  • Copy link
  • Flag this comment
  • Block
Taggart
@mttaggart@infosec.exchange replied  ·  activity timestamp 2 days ago

@lnicola In tests, but not really for production code. assert! doesn't provide graceful handlers for failure modes.

  • Copy link
  • Flag this comment
  • Block
Russell
@zimzat@mastodon.social replied  ·  activity timestamp 2 days ago

@mttaggart If people aren't supposed to use it then it should be removed from tutorials and linters should default to alerting, otherwise the language will get the same reputation as, say, PHP because practically every tutorial I've seen about Rust teaches it the wrong way by default and rarely mentions the different correct ways.

I would consider going as far as deprecating it since it's such a massive foot-gun.

  • Copy link
  • Flag this comment
  • Block
Taggart
@mttaggart@infosec.exchange replied  ·  activity timestamp 2 days ago

@zimzat It's a design choice to panic sometimes. It has its uses, but not in code that must never panic.

Linters absolutely have this config, and as far as tutorials, I don't think the Book could be clearer.

It sounds like you're asking a language to prevent introspection into an enum's values, which doesn't make a lot of sense to me.

https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#shortcuts-for-panic-on-error-unwrap-and-expect

Recoverable Errors with Result - The Rust Programming Language

  • Copy link
  • Flag this comment
  • Block
Russell
@zimzat@mastodon.social replied  ·  activity timestamp 2 days ago

@mttaggart To repeat:

The linters don't have it _on_ by default, meaning it's a foot-gun every newbie will hit directly into production. If it takes the wizened knowledge of the tribe to prevent that then the language needs to improve. Occasionally valid usage is no excuse, especially given the language has per-line overrides (double opt-in).

When I evaluated Rust initially and saw `unwrap` everywhere it seemed like a hot mess. Calling it `unwrap_or_panic` would make it obviously problematic.

  • Copy link
  • Flag this comment
  • Block
Hans-Cees 🌳🌳🤢🦋🐈🐈🍋🍋🐝🐜
@hanscees@ieji.de replied  ·  activity timestamp 2 days ago

@mttaggart @zimzat yes it's design code to panic sometimes. And there's a reason people to do unconscious sometimes because of desease don't get a drivers license. 👍

  • Copy link
  • Flag this comment
  • Block
CounterVariable
@counterVariable@mstdn.social replied  ·  activity timestamp 2 days ago

@mttaggart ROFL, it looks like they had a return type and everything.

  • Copy link
  • Flag this comment
  • Block
Taggart
@mttaggart@infosec.exchange replied  ·  activity timestamp 2 days ago

@counterVariable append_with_names() almost certainly returned a Response. But fetch_features() returned a unit type. Not great.

  • Copy link
  • Flag this comment
  • Block
Space Invader
@spaceinvader@social.securitytheater.net replied  ·  activity timestamp 2 days ago

@mttaggart TIL. Do linters flag this?

(I do not write mission critical Rust. Or even important Rust. Just learning the language, slowly. )

  • Copy link
  • Flag this comment
  • Block
Taggart
@mttaggart@infosec.exchange replied  ·  activity timestamp 2 days ago

@spaceinvader Yes they do!

https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used

  • Copy link
  • Flag this comment
  • Block
Space Invader
@spaceinvader@social.securitytheater.net replied  ·  activity timestamp 2 days ago

@mttaggart Very cool. I can barely code without a linter, and the tips have definitely made me a better coder. Things usually compile by the second try 😛.

But also… it’s concerning that something so easily detected by the simplest of static analysis tools doesn’t seem to have been in use for this very important code.

  • Copy link
  • Flag this comment
  • Block
jerome
@jerome@strings.io replied  ·  activity timestamp 2 days ago
@mttaggart I find most unwraps are opportunities to refactor code to remove the necessity to unwrap (basically removing impossible code paths / states)
  • Copy link
  • Flag this comment
  • Block
tuban_muzuru
@tuban_muzuru@beige.party replied  ·  activity timestamp 2 days ago

@mttaggart

Heh. I learned that the hard way, and I'm a novice to Rust

Change this:

let value = some_function().unwrap();

to this:

let value = some_function()?;

Stops panics and instead gracefully returns the Err up the call stack to a function that can handle it. This is how idiomatic Rust handles errors.

  • Copy link
  • Flag this comment
  • Block
Taggart
@mttaggart@infosec.exchange replied  ·  activity timestamp 2 days ago

@tuban_muzuru The gotcha here is that this only works in functions that return a Result<T, E>, where E is a type that implements the Error trait, and that the compiler can convert from any error created by ?.

I often use if let blocks or just bite the bullet and use a full match rather than hide that complexity.

  • Copy link
  • Flag this comment
  • Block
tuban_muzuru
@tuban_muzuru@beige.party replied  ·  activity timestamp 2 days ago

@mttaggart

I have learned from others how to handle i/o errors idiomatically: any decent programming language lets you make a horrible mess of this - try to be consistent.

let data = network_call().unwrap_or_else(|err| {
// Log the error for later analysis
eprintln!("Network call failed: {:?}", err);
// Return a default value or gracefully exit the local block
Vec::new()
});

  • Copy link
  • Flag this comment
  • Block
Taggart
@mttaggart@infosec.exchange replied  ·  activity timestamp 2 days ago

@tuban_muzuru Okay, although I'm pretty sure both options I just described would also be considered idiomatic.

  • Copy link
  • Flag this comment
  • Block
The Duke of Fall :d6:
@valthonis@dice.camp replied  ·  activity timestamp 2 days ago

@mttaggart One of the first impressions I got while digging into Rust was that *some* unwrapping was useful but LOTS of unwrapping was a code smell.

Encouraged to see that understanding appears to track.

  • Copy link
  • Flag this comment
  • Block
Log in

bonfire.cafe

A space for Bonfire maintainers and contributors to communicate

bonfire.cafe: About · Code of conduct · Privacy · Users · Instances
Bonfire social · 1.0.0 no JS en
Automatic federation enabled
  • Explore
  • About
  • Members
  • Code of Conduct
Home
Login