Taming the UB Monsters in C++
herbsutter.com
herbsutter.com
Look at it this way --- mature products like Chrome are already doing all of that wherever they can. If it was enough, they wouldn't worry about C++ UB anymore. But they do.
I know several people on various C++ committees and by and large their opinion is, we evolve the language and library to give existing projects incremental improvements without asking them to rewrite them, but if you are starting with a new project C++ is often a subpar option. From that perspective I get why they'd be hesitant about efforts like Circle. Circle and co. ask developers to rewrite their code, in something that looks very different to normal C++ - whatever normal C++ even is, given the multitude of dialects out there - can't seamlessly interop with existing code, needs a new incompatible standard library, that as of now doesn't even exist. At which point, honestly just rewrite it in Rust instead of going through the painful exercise to use something that's 10+ years behind where Rust is today in terms of DX, tooling and ecosystem.
But all that doesn't explain why at the very top, even mentioning Rust as an alternative seems taboo, idk.
In the early ISO days, the people sent to ISO were employees from compiler vendors, and existing practice was the key factor into adding stuff to the standard.
Eventually, comitee dynamics took place, and nowadays most of the contributors to WG21, and to lesser extent WG14 (which still keeps more close to the existing practice spirit), you have hundreds of contributors wanting to leave their historical mark on the ISO standard, withough having written a single line of compiler code, validating their proposal, which they are able to fight trough the whole voting process, and then leave the compiler vendors sorting out the mess how to implement their beloved feature.
Those of us that really like C++, are also kind of lost on how things turned out this way.
This has been my biggest problem, and I say this as someone who has been on and off developing C++ for over 2 decades.
At the same time, it’s a safe bet to say that C++ will still be around in another 2 decades.
Which would limit most "outsider" proposals mostly to library features, which would be a good thing I guess.
[1] C++ has only 4 implementations these days, Clang, EDG, GCC, and MSVC; everything keeping up with the standard is a fork of one of these projects.
Not that WG21 won't produce further ones, just like has happened with other ecosystems of similar age, who cares about Fortran 2023, or COBOL 2023 revisions, despite their critical use in many research projects, or companies infrastructure.
It is already good enough (minus the security issues), for the existing infrastructure that relies on C++, and most of the new stuff isn't helping.
Rust is even framed as an "attack on C++" by Stroustrup himself [1]. No wonder it's taboo.
[1] https://www.theregister.com/2025/03/02/c_creator_calls_for_a...
Not trying to take a position about if it's sensational or not, just wanting to add a primary source here.
[1]: https://cwe.mitre.org/top25/archive/2024/2024_cwe_top25.html
It comes from MITRE (https://en.wikipedia.org/wiki/Mitre_Corporation), and the methodology is explained on the website (roughly, the score is relative prevalence times relative average vulnerability severity).
> and attackers can switch to it, so shutting off one source of UB isn't as effective in practice as you might expect.
If that's how things work, you could say the same about all the other weaknesses that have nothing to do with UB.
It is true to say that memory-safety issues are among the biggest problems in C and C++, but it is not true to say that unless you absolutely prevent them all you remain in the same spot. If you significantly reduce or prevent some of the memory safety issues, you're in a place that's not too different from that of programs in memory-safe languages.
There is also the whole issue that standard working group, and the folks that actually work on C and C++ compilers, nowadays it is a very thin Venn diagram for the intersection of both groups.
So it remains to be seen how much of this will actually land on compilers, and in what form.
Nevertheless there are many C++ written tools that most likely will never be rewritten into something else, so any improvement is welcomed.
Which I think it was much better back when it was C++ vs C in the C++ARM days, with great compiler provided frameworks, eventually past C++98 there seems to have been an inversion, as C++ graduality took over domains where C ruled.
The same mideset that will reach out for unsafe language constructs, regardless of the programming language, without any kind of profiler information, because of course it is faster and every μs counts.
1. who says it hasn't?
2. most of the vul code is C, which is obviously much harder to harden, and the Rust Evangelism Strike Force loves to pretend that C++ is the same as C, so no matter the improvements to C++, they will just point at C.
3. I think many simply didn't know about these hardening modes, MSVC has had this for 10-15 years, but I still encounter people who don't know about it..somehow.As long as that C code is valid C++ code, it’s still a problem for C++. Backwards compatibility with C is a strength, but also a weakness. The Go and Java folks invested in rewriting dependencies in their own language to prevent problems, if C++ is truly that much safer than C, the C++ community could do the same, and demonstrate that it’s safer.
This is the power of opt out vs opt in. You can’t forget to run the borrow checker in Rust. That’s a practical, real-world advantage.
And even if this would all be available today, you would need to wait 10 years for all third party libraries to catch up. Just look at the current rate of c++ version adoption. Many projects just migrated to c++17 this year, and that version is 8 years old by now...
Edit: Just used PCL that got updated from c++14 to 17, or look at https://vfxplatform.com/ where everything is c++17, and the list goes on....
Having said this, I think the sudden and almost exclusive focus on memory safety is weird. As a long-term Linux user, this is not my main problem. This is what people building app stores and non-free content distribution systems need and they now re-engineer the world according to their needs. There are lot of things compromising my online safety and freedom, and certainly memory safety issues are not very high on this list.
Finally, what Rust achieves, and what a memory-safe mode in C will hopefully also achieve in the future, is also just an incremental improvement. As long as there in unsafe code, and in practice there will be a lot of unsafe code, there is no perfect memory safety.
Also, I question your claim that memory unsafety is not of great importance to regular computer users. Perhaps not if your computer is airgapped from the internet and never gets any unvetted software installed. Otherwise, have you missed the primary cause of the majority of CVEs issued in the past decades? Do you not think that the main technical problem behind countless security vulnerabilities, that have very concretely affected tens and hundreds of millions of people, does not deserve the attention that it’s finally starting to get?
Google has reported that the mere act of stopping writing new code in memory-unsafe languages has made the fraction of mem safety vulnerabilities drop from >80% to ~20% in a few years. This is because bugs have a half-life, and once you stop introducing new bugs, the total count starts going down asymptotically as existing bugs get fixed.
Finally, since you inevitably mentioned Rust, memory safety is indeed a necessary but not sufficient condition in software reliability. Luckily, Rust also happens to greatly decrease the odds of logic bugs getting in, thanks to its modern (i.e. features first introduced in ML in the 70s) type system that actually tries to help you get things right.
C is never going to have those parts, the “if it compiles, it is correct by construction” assurance. C++ has janky, half-assed, non-orthogonal, poorly-composing, inconsistently designed versions of a lot of the stuff, but it also has all of the cruft, and that cruft is still what is taught to people before the less-bad parts. And because C++ is larger than the most people’s brain capacity, most people can’t even get to the more less-bad parts, never mind keeping up with new standard versions.
And C definitely will have memory safety. Stay tuned. (And I also like to have memory safety.) I do not care about C++ nor do I care about Rust. Both languages are far too complex for my taste.
Only because CVEs are never issued when humans are compromised. While that is probably the correct action on their part it means your argument is flawed as you don't account for human vulnerabilities which are much more common. Yes memory safety is a big problem and we should do something - but as an industry we need to not ignore the largest problem. There is a lot we can do in UX to prevent most security vulnerabilities, and putting too much emphasis on memory can take away from potentially more productive paths.
But how many of those updates fix memory issues?
Last I checked (a few months ago) 8 out of 10 breaches were due to human error.
As far as reducing breaches go, you'll get more bang for your buck by ensuring employees are up to date on their routine security awareness training.
Your employees are much much easier to hack than your computers. "Choice of language" is a blip in the stats.
There is a lot we can do in UX to make human vulnerabilities less common, but no language change will help.
While unauthorized people waltzing on in to company premises hasn't not happened, it's been way rarer than the amount of serious bugs or security flaws I find. Traditional phone and email scams happen more often, but their impact has materialized much less severe thanks to very limited user privileges
Currently there has been negligible impact on any of the products I've looked over because of traditional human scams. Conversely there have been significant troubles from real exploits being found and abused in the wild with dire consequences for legal and financial, but maybe my experience just happens to heavily skew the opposite of norm?. I expect things to change in the medium-term future as LLMs and such improve so that they can generate coherent text above a single sentence
They're clearly panicking about people switching to Rust. I don't think it's surprising. Too little too late though; you can't just ignore people's concerns for decades and then as soon as a viable competitor comes along say "oh wait, actually we will listen to you, come baaack!".
> There are lot of things compromising my online safety and freedom, and certainly memory safety issues are not very high on this list.
Out of the things that programming languages can solve, memory safety should be very high on your list. This has been proven repeatedly.
All that said, I would love a language that had the same guarantees and performance without the complexity, but I don't see how that could work. There is definitely extra stuff in rust but the core capabilities come from the type system. Getting the same safety any other way would probably require a purely functional language which has performance costs in any implementation I am aware of along with a runtime being necessary. If you can afford that, then we don't need a new c, we have those languages.
Indeed.
> but nothing I have seen so far convinces me that the reality is a lot different
https://www.memorysafety.org/docs/memory-safety/#how-common-...
This is very well studied.
> Of course, there is a lot of old crappy legacy C code
Ahh... you don't make mistakes. I see.
This is really what a lot of all of this comes down to, Herb and the committee feel like you do, others feel that the numbers won't be that good. We'll see in time!
If by "in time" you mean last year then yes...
https://security.googleblog.com/2024/09/eliminating-memory-s...
The question should less be about whether it's possible to try to abuse the system and more what it looks like in a very reasonable everyday scenario.
Here is the most recent version of NEWP manual,
https://public.support.unisys.com/framework/publicterms.aspx...
Which started as ESPOL in early 1960's,
https://en.wikipedia.org/wiki/Executive_Systems_Problem_Orie...
Binaries with unsafe code blocks are tainted, and must be white listed by admins to allow execution in first place.
This was then followed by several languages, using unsafe code blocks, pseudo packages like SYSTEM, unsafe, unchecked,..., until finally Rust came to be.
But since most C and C++ users aren't language nerds, not even reading their own ISO specification, they are unaware of the whole safety history since JOVIAL, and naturally the whole unsafe code blocks is all about Rust.
Yes, in practice they quite commonly will. `unsafe` is rare, so it’s feasible to spend lots of extra efforts to validate it.
Some projects will have more than others, for example, as you mention, interfacing with other systems or hardware. (Performance is not as straightforward.)
Even then, generally speaking it's usually pretty small: the sorta-kinda-RTOS we have at work for embedded systems is about 3% unsafe in the kernel, for example.
Surveying all of crates.io [1] almost a year ago found that 20% have 'unsafe' somewhere in them; this is expected to be higher on crates.io than in all Rust code, because crates.io hosts mostly libraries, which are going to use unsafe more than application code.
However, they also found that most of those usages of unsafe are for FFI, which is not able to be done in a safe way, and is overall easier to ensure the safety of than other forms of Rust's unsafe.
1: https://rustfoundation.org/media/unsafe-rust-in-the-wild-not...
The only thing they've shipped is no UB in constexpr code - i.e. code that wouldn't have been reachable by attackers in the first place. How could that possibly be the reason for the price of zero-day exploits increasing?
I also think Herb Sutter leaving his role at Microsoft might have been related with this.
From "Microsoft Azure security evolution: Embrace secure multitenancy, Confidential Compute, and Rust"
https://azure.microsoft.com/en-us/blog/microsoft-azure-secur...
"Decades of vulnerabilities have proven how difficult it is to prevent memory-corrupting bugs when using C/C++. While garbage-collected languages like C# or Java have proven more resilient to these issues, there are scenarios where they cannot be used. For such cases, we’re betting on Rust as the alternative to C/C++. Rust is a modern language designed to compete with the performance C/C++, but with memory safety and thread safety guarantees built into the language. While we are not able to rewrite everything in Rust overnight, we’ve already adopted Rust in some of the most critical components of Azure’s infrastructure. We expect our adoption of Rust to expand substantially over time."
From "Windows security and resiliency: Protecting your business"
https://blogs.windows.com/windowsexperience/2024/11/19/windo...
"And, in alignment with the Secure Future Initiative, we are adopting safer programming languages, gradually moving functionality from C++ implementation to Rust."
Finally,
"Microsoft is Getting Rusty: A Review of Successes and Challenges - Mark Russinovich"
Good job MS! I hope Apple follows suit soon.
In the vast majority of cases it doesn't matter what `INT_MAX + 1` does you code it wrong. Sure there are a few encryption cases where it is fine, but the vast majority of cases your code as a bug no matter what the result it. If the variable netWorth is at INT_MAX there is no value of adding 1 that is correct. If the variable employeeId is at INT_MAX all values of adding 1 are going to collide with an existing employee.
Meanwhile if you define INT_MAX+1 you force the compiler to add checks for overflow INT_MAX in addition operations even though most of the time you won't overflow and thus have needlessly slowed down the code.
UB causes real problems in the real world, but INT_MAX+1 is not one of those places where it causes problems.
Getting rid of undefined behavior will not get rid of bugs, and no one thinks that memory safe languages somehow are bug free and certainly C++ code will not be bug free even if undefined behavior is replaced with runtime checks. What eliminating undefined behavior does is it places predictable boundaries on both the region of memory and the region of time that the bug can affect.
[1] https://devblogs.microsoft.com/oldnewthing/20140627-00/?p=63...
Your code has a bug if addition overflows and there is no point in defining how it works.
Naturally whatever happens to a CPU register in isolation doesn't turn right away into a security issue.
>UB optimizations also just create mysterious ordinary bugs, such as ... “time travel” optimizations that change code that precedes the point where the UB can happen.
>Less of all those things, please.
I don't think someone saying "less of those things please" is the same as saying "we need to get rid of this or greatly restrict it".
Also once again, I really find problematic the idea that it's the existence of a bug itself in code that is the main issue. That is a standard that absolutely no language or technology can ever eliminate. The goal of any safety related proposal is not to make it impossible to write bugs, but that the consequences of those bugs are constrained in both space and time.
In particular: how do you write a library that guaranteed will not have integer overflow on any existing or future architectures and compilers?
By following the behavior in the standard, and not trying to imagine how the standard is implemented.
For example, C23 includes https://en.cppreference.com/w/c/header/stdckdint, which you can safely use to check for overflows. It's also in C++23.
If you're not on the latest standards, there are techniques to do so as well, these macros codify existing practice: https://stackoverflow.com/questions/199333/how-do-i-detect-u...
I am sure such correct code can be written, but expecting everyone to play along with standard and ignore that 100% of existing compilers have much saner behaviour, might be very difficult.
Which is to say not nearly as well as I would like.
It is quite another thing to have a big chunk of code simply missing from the compiled binary, because complier found a path that reaches integer overflow and thus decided that the code is unreachable.
What is your opinion on deploying C++ codebases with mitigations like CFI and bounds checking? Let's say I have a large C++ codebase which I am unwilling to rewrite in Rust. But I:
* Enable STL bounds checking using appropriate flags (like `-DGLIBCXX_ASSERTIONS`).
* Enable mitigations like CFI and shadow stacks.
How much less safe is "C++ w/ mitigations" than Rust? How much of the "70% CVE" statistic is relevant to such a C++ codebase?
(I've asked this in an earlier thread and also in other forums, but I never really got a response that does not boil down to "only Rust is safe, suck it up!". It also doesn't help that every other thread about C++ is about its memory unsafety...)
But the larger problem is that bounds checking (even ASAN) isn't as good as statically checking code. ie. Your code with bounds checking still crashes at run time, which can be a denial of service attack, whereas with static checking your code would never have compiled in the first place.
Nevertheless if you don't want to rewrite the world, then using these mitigations is much better than not using them. I would also add fuzzing to the mix.
But as you mention, unfortunately enabling bound checking in the STL wouldn't catch a lot of pointer manipulation.
It would still be better than the the status-quo.
But my hunch is that the vast majority of C++ codebases aren't using std::span or std::array everywhere because there is just a lot of much older code. And there's no comparable option for handling lifetime bugs.
Tools like CFI or hardware memory tagging or pointer authentication help, but skilled exploit creators have been defeating techniques like these for a while so they don't have the "at least I know this entire class of issue is prevented" confidence as bounds checks inserted into library types.
The general industry recommendation is "if you are starting something new that has security implications, please seriously explore Rust" and "if you have a legacy C++ codebase that is too expensive to port please seriously explore these mitigation techniques and understand their limitations."
But don't forget lots of open source code is written in C and this barely helps there.
Sure, but the other half are use-after-frees and those would not be exploitable anyway because of CFI and shadow stacks.
> Enable STL bounds checking using appropriate flags
This rarely helps. Most of the nice-to-exploit bugs were in older codes, which weren't using STL containers. Or they are even just write in C. However, if enabling these flags do not hurt you, please still do as it does make non-zero contribution.
> Enable mitigations like CFI and shadow stacks.
Shadow stack is meh. CFI helps a bit more, however there's some caveats depending on which CFI implementation you are talking about, i.e. how strong is it, for example, is it typed or not? But in best case it still just makes the bug chain one bug longer and maybe completely kills some bugs, which isn't enough to make your exploits impossible. It just raises the bar (that's important too though). It also depends on what the specific scenario. For example, for browser renderer without sandbox / site-isolation etc, CFI alone makes almost no impact, as in this case achieving arbitrary R/W is usually easier than taking over $rip, and it's obvious you can do data-only attack to have UXSS, which is a serious enough threat. On the other hand, if it's a server and you are mainly dealing with remote attackers and there's inherently no good leak primitive etc, various mitigations soup could make real difference.
So, all in all, it's hard to tell without your project details.
> How much of the "70% CVE" statistic is relevant to such a C++ codebase?
Uh, I'd guess, half or more of that. But still, it just raises the bar.
> This rarely helps. Most of the nice-to-exploit bugs were in older codes, which weren't using STL containers.
While I agree with this, is not modifying those code to use STL containers much cheaper than rewriting into an entirely new language?
> Shadow stack is meh.
Are you referring to the idea of shadow stacks in general or a particular implementation of them?
> For example, for browser renderer without sandbox / site-isolation etc
I may be wrong, but I think you are referring to JIT bugs leading to arbitrary script execution in JS engines. I don't think memory safety can do anything about it because those bugs happen in the binding layer between the C++ code and JS scripts. Binding code would have to use unsafe code anyway. (In general, script injection has nothing to do with memory safety, see Log4j)
> Uh, I'd guess, half or more of that.
I mean, if you are after RCEs, don't CFI and shadow stacks halt the program instead of letting the CPU jumping to the injected code?
Now, let me get more specific - can you name one widespread C++ exploit that:
* would have happened even if the above mentioned mitigations were employed.
* would not have happened in a memory safe language?
> is not modifying those code to use STL containers much cheaper
That's right. However, I'd add that most exploited bugs these days (in high-profile targets) are temporal memory safety (i.e. lifetime) bugs. The remaining spatial (out of bound) bugs are mostly in long forgotten dependencies.
> Are you referring to the idea of shadow stacks in general or a particular implementation of them?
The idea. Shadow stack (assuming perfect hardware assisted implementation) is a good backward-edge control flow integrity idea, and ruins one of the common ways to take over $rip (write a ROP chain to stack), but that's it. Besides making exploitation harder, both forward-edge and backward-edge CFI also kill some bugs. However, IMO we are long past non-linear stack buffer overflow days, once in a while there may still be news about one, but it could be news because it is an outlier. Hence, compared to CFI, the bugs shadow stack kills are pretty irrelevant now.
> JIT bugs leading to arbitrary script execution in JS engines
Not necessarily JIT bugs. Could also be an UAF and people went a bloody path to convert it to an `ArrayBuffer` with base address = 0 and size = 0x7FFFFFFFFFFFFFFF accessible from JavaScript. Chrome killed this specific primitive. But there's more, I'm not going to talk about them here.
You may have a slight confusion here. In case of browser renderer, people starts with arbitrary JavaScript execution, the goal here is to do what JavaScript (on this page!) can't do, via memory corruption - including, but not limited to executing arbitrary native code. For example, for a few years, being able to access Chrome-specific JS APIs to send arbitrary IPC message to browser process (out of renderer sandbox), is one `bool` flag on .bss away from JavaScript. If we managed to get arbitrary R/W (that is, can read / write all memory within the renderer process, within JavaScript, see my ArrayBuffer example above), we just change it and run our sandbox escape against browser process in JavaScript, who needs that native code execution?
Or, if you do want native code execution. For a few years in V8 the native code WASM gets compiled to, is RWX in memory, so you just use your arb R/W to write that. You can kill that too, but then people starts coming up with bizarre tricks like overwriting your WASM code cache when you load it from disk and before making it R/X, and there're enough fishes in the pool that you likely can't patch em'all.
> I mean, if you are after RCEs, don't CFI and shadow stacks halt the program instead of letting the CPU jumping to the injected code?
Yeah. But as I said, nowadays people usually use temporal memory safety bugs, and they want arbitrary R/W before they attempt to take over $rip. Don't get me wrong, this is because of the success of CFI and similar mitigations! So they did work, they just can't stop people from popping your phones.
> can you name one widespread C++ exploit that:
I just google'd "Chrome in the wild UAF" and casually found this in the first page: https://securelist.com/the-zero-day-exploits-of-operation-wi...
I assume "in the wild exploited" fits your "widespread" requirement.
Granted, it's five years old, but if you are okay with non-ITW bugs I can come up with a lot of more recent ones (in my mind).
This is an UAF. So it would not have happened in a memory safe language. While back then the exploited chrome.exe may not have enabled CFG (it was enabled late 2021 IIRC), I don't see how the exploit path could be blocked by CFI.
Back in the old Usenet flamewars, C developers would to say coding in languages like Object Pascal, Modula-2, Ada,... was like programming with straightjacket, and we used to call them cowboy programming.
When C++ came into the scene with its improved type system, it seemed a way we could have the best of both worlds, better safety and UNIX/C like ecosystem.
However this eventually changed as more and more people started to adopt C++, and thanks to its C subset, many C++ projects are actually mostly C code compiled with a C++ compiler.
So hardned runtimes help a lot, as does using static analysers like clang tidy, VC++ analyse, Sonar, PVS Studio, Clion analysers, ....
However many of them exist for the last 30 years, I was using Parasoft in 1999.
The biggest problem is culture, thinking that such tools are only required by those that aren't good enough to program C or C++, naturally those issues only happen to others, we are good drivers.
As an old white man who switched from C++, for a over a quarter century, to Rust, about seven years ago, the fallacy at the root of Herb's piece is all too well understood by me.
In my experience, introducing modern C++ in a legacy codebase is not that much easier compared to adding Rust to it. It's probably safe to argue that C++03 stands to C++26 almost like K&R C stood to the original C++
- denial ← you are here
- anger
- bargaining
- depression
- acceptance
Cope, seethe, mald, etc.
I completely agree this is trying to polish a turd, essentially. The train has left the station some decades ago.
But if you have a beter compiler that points out more of the problem UB areas in your codebase, then you have somewhere you can make a start towards reducing the issues and attack surface.
The perfect is often the enemy of the good.
(edit - typo)
Human civilization is now so totally dependent on fragile, buggy software, and active threats against that software increasing so rapidly, that we will look back on this era as we do on the eras of exploding steam engines, collapsing medieval cathedrals, cities that were built out of flammable materials, or earthquake-unsafe buildings in fault zones.
This doesn't mean that safer C++ isn't a good idea; but it's also clear that C++ is unlikely ever to become a safe language; it's too riddled with holes, and the codebase built on those holes too vast, for all the problems to be fixed.
So yes, moving to safer alternatives is a very good thing. But that's going to take a long time and cost a lot of money, which we don't necessarily have. So if we can mitigate a bunch of the problems with improved C++, it is a definite win.
Let's face it, most of central Italy is still beautiful little stone towns, despite being in an earthquake zone. People still live there in stone houses because demolishing and rebuilding half the country is just not feasible. Our IT infrastructure is possibly in the same state.
That is the problem, and why we need to fix C and C++, somehow.
The safety of LLVM and GCC need not be a priority... they're not normally exposed to untrusted input. Also, it's a particularly hard area because the safety of generated code matters just as much as the safety of the compiler itself. However Cranelift is an interesting option.
No silver bullet here unfortunately... but writing new infrastructure in C or C++ should mostly be illegal.
From my experience with C++ I do expect 1. "verschlimmbessern"/aggravate-improving due to missing edge cases, 2. only spatial problems aka bound-checks to be usable (because temporal ones are not even theoretically discussed) and 3. even higher language complexity with slower compile times by front-end (unless C++ v2 like what Herb is doing becomes available).
Which as proven by the failure to push safer whole OS stacks, tends to fail on the political front, even if the technologies are capable to achieve the same.
I would have loved to Managed DirectX and XNA to stay around and not be replaced by DirectXTK, that Singularity, Midory, Inferno, Oberon, Midori,.... would gotten a place in the market, and so forth.
The mitigations in the cited article are good too, but they don't replace the need for safer languages.
Rewriting in C seems like a dodged bullet. Better for it to stay on older safer languages.
Most COBOL rewrites I have heard of went to Java, a safe language.
The nice thing about this approach is that the LLMs don't need to be flawless for it to work, as the formal analysis / unit testing will keep their errors at bay - they just need to be good enough to eventually output something that passes the tests.
... and we also need to be more paranoid about what makes its way into globally significant crates, otherwise we just trade one class of vulnerabilities for another.
We are, because we will have to, and the momentum is already gathering. Foundational tools and libraries are already being rewritten. More will follow.
> But if you have a beter compiler that points out more of the problem UB areas in your codebase, then you have somewhere you can make a start towards reducing the issues and attack surface.
Sure. But fixing those is going to be harder and less effective than rewriting.
wtf someone comes up with "X is UB" and even worse, "Since it's UB this gives a license to do whatever the f we want, including something that's clearly not at all what the dev intended"
No wonder the languages being developed to solve real problems by people with real jobs are moving forward
That’s really not how it works.
Compilers rather works in terms of UBs being constraints (on the program), which they can then leverage for optimisations. All the misbehaviour is emergent behaviour from the compiler assuming UBs don’t happen (because that’s what an UB is).
Of note, Rust very much has UBs, and hitting them is as bad as in C++, but the “safe” subset of the langage is defined such that you should not be able to hit UBs from there at all (such feasibility is what “soundness” is about, and why “unsoundness” is one of the few things justifying breaking BC: it undermines the entire point of the langage).
I think a good way to view this would be that optimization passes have invariants. The passes transform code from one shape to another while ensuring that the output from running the code remains the same. But in order for the transformation to be valid certain invariants must be upheld, and if they are not then the result of the pass will have different output (UB).