You can do a lot in regards to memory safety also in C / C++ : https://llvm.org/pubs/2006-05-24-SAFECode-BoundsCheck.pdf
Anyway. Writing safe code in C is HARD but possible. Especially with good tooling. That is not to say everyone should use C. C is an exceptionally hard language to use safely and correctly and is not for everyone.
One meta-source for this is Prossimo[0]. They link to multiple vendor reports that range from 60 - 90%.
> Writing safe code in C is HARD but possible. Especially with good tooling.
I don’t disagree in theory, but I think it is so hard as to be impractical in almost every case. So, other than maintaining a legacy code base, why try at this point when other options are available?
0 - https://www.memorysafety.org/docs/memory-safety/#how-common-...
What options would you recommend in 2024? I write C (not C++) and work on projects that are inherently memory unsafe (the last one required hand-written assembly code). I've explored potential C successors in the past, but have yet to discover one that matches the freedoms, simplicity, ergonomics, and performance of the C language.
And in spite of my distaste for it, I respect that it completely eliminates giant classes of vulnerabilities. You can write bad logic in any language. At least in Java you can't write bad logic that also suffers from memory issues.
Oh you bet you can. There are a number of ways to screw that up.
- memory leaks/loitering is quite common, gc won’t help if your code hangs on to stale refs
- using Unsafe memory can blow up in glorious C++ fashion, directly or indirectly
- using native calls incorrectly can be just as nasty
Now JNI on the other hand, that made up maybe 0.5% back in the day. Not anymore where FFI is the predominant native linkage (but still comparatively quite rare).
(Cue the one weird guy coming out of the woodwork who claims that all of his Java projects in the last 10 years have used Unsafe to great effect.)
Your project may not use it directly, but there’s a pretty good chance one of your libraries does.
There is indeed a difference here between the vast majority taking part in risky behavior and library authors using focused performance improvements. There are a lot more eyes on the library code due to downstream effects than in everyday top-level code.
C++ has bugs that bad that are found and weaponized daily.
So, Java is much safer probably by 2-3 orders of magnitude.
Also - the log4j thing shows just how dangerous class loading is. It’s an eval like mechanism. Probably future languages designed with safety in mind should avoid eval-like mechanisms as well as avoiding type system escape hatches.
Java's biggest mistake here, IMHO, was to have a serialization setup that was based solely on a generic interface rather than having the caller declare up front what class it expects to see. In the latter case, so long as you aren't storing naked Object/Serializable fields, type limits strongly restrict the set of naughty objects that can show up in your deserialized object graph. Rust Serde gets this right.
I think unchecked serialization is bad because it leads to that “given a string you get an instance of the class named by it” problem.