4 ms·
No, but I'm pretty new to rust and haven't written enough code to know how often situations that call for unsafe code blocks come up. (My current project I'm u
by elihu 10y ago
No, but I'm pretty new to rust and haven't written enough code to know how often situations that call for unsafe code blocks come up.
(My current project I'm using to learn Rust is to port a ray-tracer I wrote in Haskell. I wouldn't expect functional-style code to require a lot of unsafe blocks and I haven't needed any yet, but who knows?)
- steveklabnik 10y agoCool, just wondering. In general, unsafe code should be encapsulated, to isolate its possible effects, and once you've got it isolated, it's easy to break that bit out in a library.
- vvanders 10y agoFrom poking around in Rust for ~1 year my common ones are uninitialized arrays for scratch buffers(> 1Kb) and FFI(obviously). Like you said all the other cases are nicely wrapped into a library but I'm not quite sure how you'd abstract the first one above. It's small enough to do the unsafe block inline that it's not annoying but definitely shows up(esp when you hit APIs that are copy of C interfaces).
- steveklabnik 10y agoDepends on what you're doing; see https://crates.io/crates/init_with https://crates.io/crates/init_with as one example. It's not the exact same thing, and yeah, I would argue that's one area where it's okay to not totally abstract it. Rules are meant to be broken. (I was thinking about removing bounds checks with get_unchecked as well).
- vvanders 10y agoThat's a much more involved use case that I usually have. Looks like a solid abstraction though. Like I said, not really an issue, just a common pattern that I see.
- steveklabnik 10y agoAbsolutely, understood. Ironically, this is also a good example of how unsafe is complicated; "hey make an array (not vector) of copies of this thing" has lots of edge cases!
- Animats 10y agoI listed two things Rust doesn't handle well without unsafe code, doubly linked lists and multidimensional arrays. Here are examples of both from popular repositories with high download numbers: - https://github.com/andelf/rust-adivon/blob/master/src/deque.rs https://github.com/andelf/rust-adivon/blob/master/src/deque.... - https://github.com/andelf/rust-adivon/blob/master/src/queue.rs https://github.com/andelf/rust-adivon/blob/master/src/queue.... These are all the doubly-linked list problem: struct Node<T> { item: T, next: Option<Box<Node<T>>>, prev: Rawlink<Node<T>> } Since this is templated code, it might be possible to break it by instantiating it on a type with unusual semantics. - https://github.com/BurntSushi/aho-corasick/blob/master/src/full.rs https://github.com/BurntSushi/aho-corasick/blob/master/src/f... Looks like unsafe code for "performance reasons". But there are no comments near "unsafe", so it's hard to tell. - https://github.com/SiegeLord/RustAlgebloat/blob/master/algebloat/src/index.rs https://github.com/SiegeLord/RustAlgebloat/blob/master/algeb... Matrix math. "Unsafe" all over the place, and unsafeness is exported, allowing the caller to do unsafe things. This is an example of why I occasionally stress the need for multidimensional array support at the language level. If the compiler knew about multidimensional arrays, it could optimize the subscript checks for them, avoiding code such as this. The unsafe version. The caller can store anywhere in memory. fn unsafe_set_idx(&self, $mat: &T, v: f64) { let $self_ = self; let (r, c) = $rc_expr; unsafe { $mat.raw_set(r, c, v) } } Safe, but inefficient version. The compiler can't hoist those checks out of loops. fn set_idx(&self, $mat: &T, v: f64) { let $self_ = self; let (r, c) = $rc_expr; assert!(r < $mat.nrow()); assert!(c < $mat.ncol()); unsafe { $mat.raw_set(r, c, v) } } This is the sort of thing that leads to exploits in code that reads things like JPEG files. Yet you can't do much better in Rust. That's why doing multidimensional arrays in macros and templates isn't good enough.