13 ms·
Is Rust Used Safely by Software Developers?
- nicolashahn 5y agoDisclaimer: Rust groupie. Technically no (only for half of libraries) but effectively yes, if you're comparing to C and C++. The fact that there might be an `unsafe` somewhere in your dependency tree just means that instead of being there being a 0% chance of a memory bug, there's 0.0001%. Whereas a C/C++ codebase of moderate size is virtually guaranteed to have many (orders of magnitude might be off but point stands).
- Zababa 5y agoI think the problem here is not the absolute safety but the illusion of safety. You approach problems differently when you expect memory bugs to appear compared to thinking the chance is 0%.
- joshuamorton 5y agoI don't think this is as strong a claim here as you think. The point of unsafe is to point you toward the areas you need to audit. Unsafe code can't be proven memory safe by the compiler [...but the rest can be]. It's far easier to audit 10 or 100 LoC of unsafe rust than 10 or 100 thousand of C++. And even in C++ there are subsets of the language that are supposedly memory safe. But even when writing in those subsets I'm not convinced that the abstractions I'm building on are as well validated as rust.
- yakubin 5y agoA study of the frequency of memory corruption in rust programs would be useful here. If the real-world frequency is let's say <0.1% of bugs uncovered, then I say this mindset is a blessing. Working with C++ the feeling of paranoia you have with 1/3[1] of bugs reported, that maybe again it's memory corruption, is sucking the energy out of developers. [1]: That's the frequency of this paranoia creeping in that I observed, not of detected memory corruption, but that too I think would be counted in an integer number of percents IME.
- Zababa 5y agoThat's a great point. Their study is a good starting point but it's hard to get anything concrete out of it. I hope they can continue with something like what you proposed.
- pornel 5y agoThe real-world data shows that most Rust libraries fail due to (memory-safe) panics or logic errors leading to resource exhaustion, but plain old memory corruption is quite rare: https://github.com/rust-fuzz/trophy-case https://github.com/rust-fuzz/trophy-case
- pcwalton 5y ago> You approach problems differently when you expect memory bugs to appear compared to thinking the chance is 0%. The chance is never 0%, and nobody should be thinking that way. Memory safety bugs routinely arise in JITs (e.g. JavaScript engine CVEs). In fact, memory safety issues routinely arise in CPUs (e.g. rowhammer). In reality, terms like "memory safety" are rarely ever exact, but they're still useful descriptions. Practically, people should be thinking about frequencies, not in black and white.
- cogman10 5y agoYup. I've created a memory leak in java. Not a "I forgot to free memory in a map" memory leak but a honest to goodness "This JVM is allocating heap space and losing track of that allocation". Something that required me to install a special malloc in the VM to track down the leak. This was using standard libraries (You can do it too! Go play with the Deflater and Inflater API and you'll find it makes calls off to Zlib. If not properly handled you end up leaking heap allocations). That was the first and only time I've ran into that issue, but I ran into that issue. The guardrails rust gives you are essentially the same that the JVM gives you. That is, use only safe code and (barring a compiler bug) you are safe. However, bad things COULD (not will) happen if you use unsafe blocks. Just like bad things can happen in JNI blocks or places where Java makes use of C libraries for functionality. And that is what makes rust fantastic. It's got memory safety up there with JVM safety without a garbage collector. It even has nifty keywords (unsafe) to keep developers on their toes when they need it. Just like Java's JNI or Pythons C extensions. In fact, I'd argue that rust unsafe ends up being more safe than either JNI or C extensions primarily because it is something that can be audited very quickly across all rust code bases. Have a memory issue? It's in the unsafe block.
- adkadskhj 5y agoThere is no illusion of safety. It's 100% safe, within the code you right, if you don't use unsafe. If there is unsafe in code you use (write or shared), it's a handful of lines which you can nearly grep for it's so easy to locate. Rust devs (like myself) aren't illusioned into believing that my code and _everything below it_ is 100% safe. However i can positively assure you my code is 100% safe. Well, assuming no bug in Rust-lang/compiler. My _programs_ are not guaranteed to be 100% safe unless no unsafe is used, but Rust lets you know for certain what is safe, and what is unsafe. The point isn't absolute safety in your program. The point is absolute safety where you think there is absolute safety. To strictly know what is unsafe. And to reduce the total lines that are unsafe. edit: I'm confused by the downvotes, what is incorrect or controversial about this?
- simion314 5y agoLet's not forget that there are other languages that are memory safe and might be good enough for many tasks, so limiting the comparison only with C/C++ feels unfair to me.
- vlovich123 5y agoEvery serious C/C++ shop I've seen is seriously considering incorporating or switching to Rust. I don't think that's true for many other languages unless they would otherwise be switching to an unsafe language like C/C++ for performance reasons, which is probably a minority.
- simion314 5y agoAre they switching mid project and doing the "Rewrite It in Rust" meme? Or only for new project? If for new projects what type of project that is not some kernel, browser or some low level library is Rust the best tool for the job? For most type of projects I am thinking Python,Java, C#, C++ still is better .
- jensvdh 5y agoGame Servers?
- Jetrel 5y agoAny codecs or anything like that seem like a screamingly good target. Right now they're one of our most egregious sources of security vulnerabilities (mostly due to a lot of hands-on bit-twiddling that results in a lot of possibilities for overflow). It's gotten bad enough that a number of system developers (browsers, OSes) have been shifting to a model where codecs are strictly sandboxed, and just get a single binary input blob, and a single output blob, and don't get any other kind of access to the system they're on - it's a scorched earth problem, but it really is that bad. The thing about trying to write one with Rust is, if you actually 'went with the flow of the language' and didn't just immediately pop into `unsafe`, you'd be able to write a really safe codec. -but- The real payoff is that the performance would be surprisingly good - usually a suggestion like the one I just made would absolutely wreck performance, but one of the big things about Rust is that because it lets you describe what your intent is as a programmer in such higher-level terms (despite being a machine-level language), it gives the compiler a lot more information about the scope of your intent, which opens the floodgates to potential optimizations. For a really easy example - Rust does all variables as "immutable by default". When you're programming in C, and something is compiling your code, there are tons of opportunities where you'd go "oh, well we already calculated this, why don't we just cache it?" But the compiler can't, because it doesn't actually know what you, the human, know - that that thing won't change. Because that knowledge is available to the compiler through Rust, the compiler actually DOES know, so tons of things can get inlined, cached, and otherwise optimized for you which you'd otherwise have to do by hand. Usually when people do these sorts of things by hand, they'll ace a couple key optimizations (usually things that show up in profiling hotspots) and completely overlook hundreds, even thousands of other potential optimizations. There are tons of other "high level intent" things that give the compiler more info it can use to optimize, but the "immutability by default" one is a really easy one to explain.
- onei 5y agoThe title is a little misleading, and the results are at a glance a little alarming. If you base your definition of safe on whether you or your dependencies use unsafe anywhere, then obviously you're going to find something of concern. However, if you measure the safety of your code line by line, then the results are much better. Similarly, there's a balance to be found when assuming unsafe code is unsound. The question is ultimately a reminder to check your dependencies to make sure they're active and take reasonable steps for validating unsafe code.
- qzw 5y agoFrom the abstract: > Our results indicate that software engineers use the keyword unsafe in less than 30% of Rust libraries, but more than half cannot be entirely statically checked by the Rust compiler because of Unsafe Rust hidden somewhere in a library's call chain. We conclude that although the use of the keyword unsafe is limited, the propagation of unsafeness offers a challenge to the claim of Rust as a memory-safe language. I don’t think it’s accurate to say that any use of unsafe necessarily propagates to all code in the call chain. Often safe abstractions are built around the unsafe blocks to effectively limit the scope of unsafeness. It’s not clear from the abstract whether this analysis accounts for such scenarios.
- tialaramex 5y agoMaybe it would be a fun blog project. Take popular crates.io crates which have safety wrappers (unsafe code, wrapped in a safe function, we aren't interested in crates that just expose an unsafe function, or are purely safe) and: Each week pick a safety wrapper at random, and take it to pieces. Is the safety rationale convincing? Missing altogether? Bogus for some reason? This seems like it's potentially an interesting exercise, it's educational, and if you find any bugs this way you improve the ecosystem for everybody. Mmm. Am I missing a reason this would be a terrible idea?
- kibwen 5y ago> Am I missing a reason this would be a terrible idea? Nope, people in the Rust community love seeing these sorts of things. Here's one from just last week where someone went through and fuzzed all the popular HTTP client libraries, which went on to become the third-most upvoted post on /r/rust of all time: https://www.reddit.com/r/rust/comments/oir1g1/ive_tested_rust_http_clients_again_found_over_50/ https://www.reddit.com/r/rust/comments/oir1g1/ive_tested_rus...
- woodruffw 5y agoInteresting paper. Here's one of their key conclusions: > Our analysis shows that while publicly available Rust libraries rarely use the unsafe keyword (even very popular libraries), most of them are still not Safe Rust, because of unsafe use in dependencies. I think this might be a misapprehension of safety in Rust by the authors: safety doesn't mean that absence of the `unsafe` keyword in your dependency tree, it means safety by construction through safe wrappers of fundamentally unsafe code. The Rust standard library is the perfect example of this: it exposes safe interfaces that are built on top of fundamentally unsafe OS primitives and system calls. That doesn't make any code that uses them "unsafe"; it parametrizes the notion of safety on safe abstractions. That's all Rust has ever promised, and it's still significantly better than the status quo. Other than that, the paper's other observations are excellent: we should be more aware of the presence of `unsafe` in our dependency trees, and that information should be more readily surfaced by standard tooling. Tools like `cargo geiger`[1] and `siderophile`[2] (FD: my company's tool) bring us a little closer to that. [1]: https://github.com/rust-secure-code/cargo-geiger https://github.com/rust-secure-code/cargo-geiger [2]: https://github.com/trailofbits/siderophile https://github.com/trailofbits/siderophile
- k__ 5y agoI never understood that logic. You can write perfectly safe code in C where virtually everything is unsafe in the sense of the unsafe keyword. To my understanding, the idea of unsafe is that you now leave the guard rails that Rust provides and have to think for yourself.
- setpatchaddress 5y agoExcellent -- so your large C codebase is free of security bugs, something no software vendor has managed to accomplish. Ritchie and Thompson themselves didn't manage that feat. Tell us how you do it, please, so the world may learn.
- throwaway_c2 5y agoOh, that’s actually simple. Enforcing the “malloc once” rule gets you like halfway there, and using custom hardened code for common stuff like string manipulation finishes the job. Things like that are why some C codebases are large in the first place - you have to reinvent your own safe space from scratch. The funny thing is that it’s actually harder to protect from certain classes of bugs in Rust. For example, you cannot uncouple from the global allocator as easy as you can in C/C++, and if you do, you do it with “unsafe” code. That doesn’t make Rust a bad language, it’s just that you can see some of the inherent flaws only if you had written safe C code previously and then you find out that some basic techniques don’t translate.
- blippage 5y agoI'm not a Rust programmer, so be gentle with me. What worries me is that when it comes to safety, surely the chain is as strong as the weakest link? You declare one thing unsafe, and then suddenly all bets are off. And maybe you don't even know that what you're doing is unsafe. But here's an example I pulled from github, which blinks a Raspberry Pi Pico: // Set GPIO25 to be an output (output enable is set) p.SIO.gpio_oe_set.write(|w| unsafe { w.bits(1 << 25); w }); Right, but what if you're fiddling with registers that might require atomic operations? Lines such as this seem to be saying "ignore all that, write to the register anyway." Fearless concurrency, you say: are you sure? How do you know? Suppose you have an ISR (interrupt service routine) that wants to toggle a GPIO pin. From whence does it borrow the privilege to set the pin? Surely, at the end of the day, microcontrollers can be characterised as large state machines with global state. That's what they ARE. It's their inherent nature, which you cannot abstract away without it leaking somewhere (at least to do anything useful, anyway). At least with C/C++ you KNOW you've got a problem, and have to reason about the problem carefully. With Rust, you THINK you've solved the problem, but have you? "Change My View", as they say on Reddit. *Update 1* OK, I'm going to press my point on this. I'm looking at the Embedded Rust Book (please remember, I'm not a Rust programmer) at https://docs.rust-embedded.org/book/concurrency/index.html https://docs.rust-embedded.org/book/concurrency/index.html I'm considering the issue of interrupts here. " Instead, our interrupt handlers might be called at any time and must know how to access whatever shared memory we are using. At the lowest level, this means we must have statically allocated mutable memory, which both the interrupt handler and the main code can refer to." "In Rust, such static mut variables are always unsafe to read or write, because without taking special care, you might trigger a race condition, where your access to the variable is interrupted halfway through by an interrupt which also accesses that variable." RIGHT, but that means that Rust gives me no better assurances than C/C++. Here's their code: static mut COUNTER: u32 = 0; #[entry] fn main() -> ! { set_timer_1hz(); let mut last_state = false; loop { let state = read_signal_level(); if state && !last_state { // DANGER - Not actually safe! Could cause data races. unsafe { COUNTER += 1 }; } last_state = state; } } #[interrupt] fn timer() { unsafe { COUNTER = 0; } } Then is says "Can you spot the race condition? The increment on COUNTER is not guaranteed to be atomic" It then solves the problem by showing how to introduce a critical section. So at the end of the day it's just C with different syntax, and a lot more hoopla. You've made everything mutable and unsafe. Exactly the kind of thing you were trying to avoid in the first place.
- nynx 5y agoThis paper is surfaced pretty often and it's misleading. Rust is all about making abstractions around unsafe code that cannot be used unsafely.
- epage 5y ago> We conclude that although the use of the keyword unsafe is limited, the propagation of unsafeness offers a challenge to the claim of Rust as a memory-safe language. By this definition, is there any memory safe language? They all boil down to unsafe dependencies. Even if you ignore interpreter abstractions, any language with FFI is unsafe but without any way to audit it.
- gjffkk 5y agoSafety