Having a well-defined memory model is important when running on infra with very different models, such as x86 and aarch64.
Oh, wait, it exists https://docs.oracle.com/javase/8/docs/api/java/util/Optional...
That's a sound deduction. The JVM had such a vulnerability because it's full of ambient authority and rights amplification patterns. More such vulnerabilities probably exist, they're just hard to see.
I haven't tested this code, and definitely don't do this.
This code is intended to lets attackers run any shell command by sending JSON with a "debug_command" field - similar to Log4J, it's a "feature" being misused rather than a memory bug that Rust would catch.
```rust
use serde_json::Value;
use std::process::Command;
fn process_log_entry(log: &str) {
// UNSAFE: Allows command injection
if let Ok(json) = serde_json::from_str::<Value>(log) {
if let Some(cmd) = json.get("debug_command") {
Command::new("sh")
.arg("-c")
.arg(cmd.as_str().unwrap_or(""))
.output()
.unwrap();
}
}
}
```There are, of course, other good reasons to choose c and c++ over rust. And of course rust has its own warts. just pointing out that performance and memory safety are not necessarily mutually exclusive
2. Even when they exist, Rust lets you use unsafe code but only where needed. It's still much better than having your entire program be unsafe.
3. In practice Rust versions of programs are as fast, if not faster than C/C++ ones.
My experience is that Rust guides you towards defaults that tend to not hit those things and for the cases where you really do need that fine grained control unsafe blocks with direct pointer access are available(and I've used them when needed).
One of the reason is you get the whole program optimization automatically in Rust while C/C++ you need to use put the function that need to be inline in the header or enable LTO at the link time. Bound checking in Rust that people keep using as an example for performance problem is not actually a problem. For example, if you need to access the same index multiple times Rust will perform bound-checking only on the first access (e.g. https://play.rust-lang.org/?version=stable&mode=release&edit...).
Borrow checker is your friend, not an enemy once you know how work with it.
This is moving the goalposts. "Safe rust" isn't a distinct language. The unsafe escape hatch is there to make sure that all programs can be implemented safely.
The performance tradeoff is not intrinsic. Rust’s weakness is that it struggles to express safety models sometimes used in high performance code that are outside its native safety model. C++ DGAF, for better and worse.
The hardcoded safety model combined with a somewhat broken async situation has led me to the conclusion that Rust is not a realistic C++ replacement for the kinds of code where C++ excels. I am hopeful something else will come along but there isn’t much on the horizon other than Zig, which I like in many regards but may turn out to be a bit too spartan (amazing C replacement though).
Isn't Rusts's async situation "somewhat broken" in the exact same way the C++'s async situation is?
Why am I more worried than excited about a new standard?
By the way bounds checking was introduced in Turbo Pascal in 1987. Iirc people ended up disabling it in release builds but it was always on in debug.
But ... it's Pascal, right? Toy language.
Here is my favourite quote, every time we discuss bounds checking.
"A consequence of this principle is that every occurrence of every subscript of every subscripted variable was on every occasion checked at run time against both the upper and the lower declared bounds of the array. Many years later we asked our customers whether they wished us to provide an option to switch off these checks in the interests of efficiency on production runs. Unanimously, they urged us not to--they already knew how frequently subscript errors occur on production runs where failure to detect them could be disastrous. I note with fear and horror that even in 1980 language designers and users have not learned this lesson. In any respectable branch of engineering, failure to observe such elementary precautions would have long been against the law."
-- C.A.R Hoare's "The 1980 ACM Turing Award Lecture"
Guess what programming language he is referring to by "1980 language designers and users have not learned this lesson".
Not really.
It's just out of fashion. But there are really high quality current day implementation, like the one from Embarcadero (i think they acquired Borland a while ago?): https://www.embarcadero.com/products/delphi/features/design
Just sharing an anecdote: recently, I had to create Linux images for x86 on ARM machine using QEMU. During this process, I discovered that, for example, creation of initrd fails because of memory page size (some code makes assumption about page size and calculates the memory location to access instead of using system interface to discover that location). There's a similar problem when using "locate" utility. Probably a bunch more programs that have been successfully used millions, well, probably trillions times. This manifests itself in QEMU segfaulting when trying to perform these operations.
But, to answer the question: I think, one way to define memory safety is to ensure that the language doesn't have the ability to do I/O to a memory address not obtained through system interface. Not sure if this is too much to ask. Feels like for application development purposes this should be OK, and for system development this obviously will not work (someone has to create the system interface that supplies valid memory addresses).
- out-of-bounds on array read/write
- stack corruption such as overwriting the return address
It doesn't directly say "you can't use C", but achieving this level of soundness in C is quite hard (see sel4 and its Coq proof).
Meanwhile, everything else passes under the guise of "safety and security".
Users should have control and trust in their devices. If they can be remotely compromised, they cannot get that.
Meanwhile the rest of the population gets pushed towards authoritarian dystopia.
Users should have control and trust in their devices.
I think that already went away once they started adding spyware ("telemetry" being the usual euphemism) and forced automatic updates ("remotely compromised", as you put it.)
We're living the inbetween and people are beating the drums that drive us towards either endpoint. Not for no reason either. Turbulent times.
No need for rust, Ada, CHERI, SPARK, etc.
Moreover, if I remember correctly, they all are made possible by a single (long-standing) compiler bug that eventually will be fixed.
Previously discussed: https://news.ycombinator.com/item?id=39440808
I think this mindset is the big difference. We're not perfect, but we're working on it.
Why remove the refrences in the TR to frama-C, cbmc, etc. from the opinion report? They are easier to adopt than the heavier tooling of coq, etc. I'm always suprised to see those tools ignored or downplayed, when it comes to these discussions. I do agree with the TR's sentiment that we need to improve accessibility and understanding of these tools, but this is not a great showing for that sentiment.
Additionally, both articles miss that compiler modified languages/builds are a path, such as fbounds-safety. They will be part of the solution, and frankly, likely the biggest part at the rate we are going. Eg. current stack defenses for C/C++/Rust, unaddressed in safe language design, are compiler based. The compiler extension path is not particularly different than cheri, which requires a recompile with some modifications, and the goal of both approaches is to allow maintainers to band aid dependencies with minimal effort.
The TR handwaves away the question of the complexity of the development of formal method tools for Rust/Unsafe Rust and C++. Ie. rust really only has two tools at the moment: miri and kani (which is a cbmc wrapper). Heavier tools are in various states of atrophying/development. And C++ support from the c family of formal tools such as frama-C, is mostly experimental. It's not assured, that with the continued language development rate of both languages and the complexity of the analysis, that the tools for these languages will come forth to cover this gap anytime soon.
I do not think the claim in the TR that the current unsafe/safe seperation will result in only requiring formal analysis of the unsafe sections is true, as logical errors, which are normal in safe rust, can cross the boundries to unsafe and cause errors, thus nessecitating whole program analysis to resolve if an unsafe section could result in errors. Perhaps it will decrease the constants, but not the complexity. If rust does further restricts perhaps more of the space could be covered to help create that senario, but the costs might be high in both usability and so on.