Inline and Sideline Approaches for Low-Cost Memory Safety in C
cl.cam.ac.uk
cl.cam.ac.uk
A few little nuggets of discussion:
Section 2.1 seems like it could stand alone if you're looking for vocabulary and definitions about memory safety.
Section 2.2 discusses type safety, and mentions C's weakness here. This is what most interests me about Rust, since the c software I spent several years working on did not contain any allocations, (I've had some short but confused conversations with rust evangelists, No, we don't malloc, we don't free, and unsafe exists on a different axis than if values put into DMA engines are sanitized). I don't think the run time solutions mentioned are the way to go, it really needs to be baked into the language, but some of these tools sound fun to play with.
Section 5.4 talks about Unions. I was mistaken about the size of unions, which I thought always (or practically always) would be the size of the largest member, but the example given shows LLVM does not always behave that way, due to alignment requirements If I understand correctly.
The array'ability of the union is going to determine the size. So if you have a pointer at a given offset in one of the union'd structures it may need to increase the size of the union so that when used in an array the pointer will always stay aligned. (Same goes for any other type with alignment requirements).
I don't think this is true anymore even for system code. As Rust demonstrates, fat pointers and apropriate compile time restrictions ensure memory and type safety with marginal performance overhead.
It's simply not a problem to bother with anymore in the 21st century, if not for the immense legacy of unsafe C/C++ code and the inertia of the industry and people.
There is no inertia here but an expected outcome. C/C++ programs are often predictable, memory issues are easy to catch, and tooling is top-notch. Good luck with other languages, except maybe with JVM/.NET platforms.
They are not. Memory-safety issues continue to impact major C/C++ codebases such as the Linux kernel and Chromium, sometimes manifesting as security vulnerabilities.
It is indeed quite possible to write memory safe C/C++ code... and it's done every day. You never hear about how memory safe and performant all that code is... you only ever hear about the rare, high profile mistakes.
The problems with languages like C++ are more about how bloated it's become. There's 30 ways to do anything in that language, and 24 of them you're not supposed to use anymore! This leads to all kinds of problems as more people touch the code over many years and C++ standards.
I'm very interested in seeing Rust mature in this space... if not for memory safety promises, then for it being a "fresh start" for systems programming without all the legacy baggage C++ has.
I don't think anyone is suggesting it will be. It's not about to supplant Ada SPARK, for instance, as Rust is far behind in terms of formal analysis.
> just like what the parent pointed out about Java and it's memory safety promises back in the day
Java does address the memory-safety issues of C and C++. You can't have a buffer overflow vulnerability in pure Java code. You can't have any kind of undefined behaviour due to memory-management mistakes in your code. You can't double-free, or use-after-free, or deference a pointer to a local variable that has gone out of scope. You can't trigger undefined behaviour through a read-before-write bug in your code.
It's possible to have a memory leak in Java, if you retain references to objects for too long, but that won't ever give rise to undefined behaviour.
Of course, there can still be bugs in a JVM, but that's another matter. All languages are vulnerable to compiler bugs.
Other languages like JavaScript do the same. It's possible to leak memory, but it's never possible to trigger undefined behaviour from JavaScript. That's a vital part of its security model.
> It is indeed quite possible to write memory safe C/C++ code... and it's done every day
That doesn't sound right.
There's a reason I gave the examples of the Linux kernel and Chromium. They're written by highly competent developers, but they still have subtle memory-management bugs. Most C/C++ codebases are written by less competent developers, but are of far less interest to attackers, so it's of less consequence. Their memory-management bugs are likely to go unnoticed forever.
I agree it's possible to write C/C++ code without memory-management bugs (there are various formal development systems for C), but it's a significant challenge. I'd hope avionics software, for instance, would be entirely free of such bugs.
> You never hear about how memory safe and performant all that code is... you only ever hear about the rare, high profile mistakes.
They're not that rare, they're a major source of serious security vulnerabilities, and languages like Safe Rust can close the door on them entirely.
> The problems with languages like C++ are more about how bloated it's become. There's 30 ways to do anything in that language, and 24 of them you're not supposed to use anymore!
Agreed. C++ is quite a lumbering monster of complexity. Ada also has a reputation for being somewhat bloated, but it's not as far gone as C++.
> if not for memory safety promises, then for it being a "fresh start" for systems programming without all the legacy baggage C++ has
Keep an eye on Zig, too. Also D and Nim, and perhaps Vala. Also the lesser-known ZZ and Dafny languages, which look very interesting.
I'm kinda confused by this. Java is an extremely popular language and dominated web services for decades.
> you only ever hear about the rare, high profile mistakes.
It's more like we constantly hear about these mistakes. Rare? What constitutes rare? Monthly CVE reports from every browser vendor?
It's just so strange to me that you would say it's rare lol it's just... so wrong?
As for memory safe C/C++ code, again, it's just kind of so absurd. Think of how much time and effort goes into testing, fuzzing, and improving C++ code from companies like Microsoft, Google, AWS, etc, and how they're still finding issues all the time. Literally hundreds of millions of dollars a year are spent on this - cutting edge, new research and tooling are developed just for this problem and it's still there.
But you're saying it's rare and actually not a problem? How do you reconcile the very public, very frequent issues with this idea? How do you reconcile companies pouring hundreds of millions of dollars into this, still discovering issues, with the idea that someone somewhere is for sure just doing it way better and it's totally memory safe?
I recently ran across your 2019 comment expanding on this point: https://news.ycombinator.com/item?id=19323616
How depressing.
The same program written in Rust can be magnitudes larger in binary size[1], which is a complete non-starter for many embedded projects (where a lot of C/C++ code is destined to live).
[1] https://dev.to/aakatev/executable-size-rust-go-c-and-c-1bna
[1] https://www.codeslow.com/2019/12/tiny-windows-executable-in-...
[2] https://github.com/johnthagen/min-sized-rust
[3] https://rust-embedded.github.io/book/unsorted/speed-vs-size....
Some of which, as you said, remove features that are needed like debugging symbols.
Without doing a single thing, though, c++ binaries are tiny compared to a rust binary. That's the difference.
To achieve small binaries with rust, one must remove nearly all the advantages of rust, including the self contained stdlib, debugging capabilities, and even runtime memory safety. What's even the point of using rust then?
In this model the attacker already can execute code on the victim's host, but the VM attempts to limit what the attacker can do via restricted APIs. It's just a completely different threat.
This is a hard problem, but not impossible. There are people who say it's impossible. The usual excuses are obfuscated code, undecidablity, need to maintain binary compatibility, etc. Those are not show-stoppers. What's needed is something that converts C to ideomatic safe Rust most of the time, and to fat-pointer slow but safe Rust when the converter can't figure out what the code is doing.
This is a job comparable to an optimizing compiler, and that's a big project. It will take money.
More detailed comments on Rust forums: [2]
Trying to patch up C is not promising. It's been tried, many times. The thesis shows most of the approaches that have been tried. GCC used to have a "fat pointer" option with checking, but it was rarely used, and has, I think, been deprecated. Putting extra info in the high bits of pointers has been tried. Memory allocation where all allocations in a block are the same size and you can look up the size of by block has been tried. Syntax changes to C have been proposed; I've been down that road.
[2] https://users.rust-lang.org/t/c-to-rust-translator/55381/14
Isn't it? It looks like the author is cherry-picking approaches that haven't worked. Isabelle and verifast do very well at making c secure, for instance.
What you end up with is a silly new language that inherits the awkward syntax of something designed in the 60s and lacks the rich expressivity and idioms of newer languages. At that point, it makes little sense to not start from scratch and work with a completely new language adequate for your application - such as Rust or Java.