rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
98.24k stars 12.71k forks source link

containers should provide some way to not panic on failed allocations #29802

Closed froydnj closed 6 years ago

froydnj commented 8 years ago

I was working on a Rust image library, which has code like:

  vec![0xff; self.num_channels * self.width as usize * self.height as usize]

This code should really be checking for overflow on the multiplications. But doing so only eliminates one class of problems with this code: it's still reasonable for a maliciously crafted image to have large self.width and self.height values whose product doesn't overflow usize and yet the amount of memory can't be allocated. (I discovered this through an image test suite that has images with...large widths and heights that ought to return errors, but panic'd in Rust.)

Looking through the documentation, I didn't see any way of avoiding this panic-on-allocation failure, either at vector creation, or when trying to append elements to a vector.

Ericson2314 commented 7 years ago

@Gankro Ah your latest comment appeared as I was writing this. Nor had I read the thread. Glad to here we all do want a lint. In light of that I think my point about making the lint easier to maintain is perhaps the best.

Relatedly, for refactoring existing Rust code, e.g. Servo, I'd want

  1. A transition feature so that the faux-infalliable methods are defined for all allocators with unwrap instead of void_unwrap.
  2. A tool to convert all .foo() to .try_foo().unwrap(), which would then making auditing far easier--grep for unwrap or try.*unwrap.
  3. Run that and disable the feature.

And again in terms of expediency, while the portability lint is not yet implemented, everything I mention an be done today. A road map could be

  1. Immediately add associated type, PanicOom, and convert all collections to use infallible allocators. No clever thinking about algorithms is needed.
  2. Collection-by-collection, see if algorithms can be tweaked to support the fallible case---easier for flat ones like Vec, a good deal harder for tree-based ones (if we don't consume the collection lest it gets in an inconsistent state).
  3. Whenever the portability lint using features is ready to go, the cargo features can be in place to support them.
Gankra commented 7 years ago

To be clear, we identified that the lint was nice to have but in no way a blocker for our users. As such we planned to punt on it and solve it more robustly with actual lints. In the mean time we could provide the methods, and users could build wrapper types to hide infallibility if they chose want.

On the topic of different collections, only BTreeMap would run into issues with a naive translation. It shouldn't be too difficult to pre-allocate the nodes before starting the mutations.

Ericson2314 commented 7 years ago

@Gankro I think expecting users to write their own wrapper types is futile because the biggest benefit is trust between libraries, but I can't see any wrapper types outside of the libcollections becoming as standard.

I also forgot to mention how error-type polymorphism allows one to convert code bases function by function.

Is there anything you dislike about mine, besides it being a lot of work in your eyes?

Gankra commented 7 years ago

RFC: https://github.com/rust-lang/rfcs/pull/2116

Mark-Simulacrum commented 6 years ago

Since the RFC was merged, and I believe future work in this area will require extensive discussion (either on internals or in RFC(s)) I'm closing this issue.