|
|
Log in / Subscribe / Register

Rust in Android: move fast and fix things (Google Security Blog)

The Google Security Blog has a new post on just how well the use of Rust is working out for the Android project.

We adopted Rust for its security and are seeing a 1000x reduction in memory safety vulnerability density compared to Android's C and C++ code. But the biggest surprise was Rust's impact on software delivery. With Rust changes having a 4x lower rollback rate and spending 25% less time in code review, the safer path is now also the faster one.


to post comments

Code Review

Posted Nov 13, 2025 20:54 UTC (Thu) by clugstj (subscriber, #4020) [Link] (21 responses)

Less time in code review? Maybe this isn't a good thing.

Code Review

Posted Nov 13, 2025 21:18 UTC (Thu) by mathstuf (subscriber, #69389) [Link]

I think one can agree that "code review time" is not correlated, at all, with quality on its own. Just like "lines of code". Sure, some good things take a few lines, some take a lot. But some bad code takes a few lines while others are FactoryFactoryBeanFactory horrors, racking up useless line counts all over the place. I have outstanding patches to GCC that are pretty simple, but have no response. Is that because they're "hard", "too trivial to bother", or are they just lost in the mailing list maelstrom? Who knows. As a raw number, it is pretty useless.

But given that while there is reduced time spent in review, there are still fewer rollbacks and issues…seems like taking less time rather than more is a good thing.

Code Review

Posted Nov 13, 2025 21:36 UTC (Thu) by tux3 (subscriber, #101245) [Link]

Sure, the reviewers were satisfied faster. But on the other hand, there were less critical bugs.

Oh Scylla, oh Charybdis!

Code Review

Posted Nov 13, 2025 21:45 UTC (Thu) by Vorpal (guest, #136011) [Link] (12 responses)

This is clarified if you read the full linked blog post rather than just the short quote:

> Code review is a time-consuming and high-latency part of the development process. Reworking code is a primary source of these costly delays. Data shows that Rust code requires fewer revisions. This trend has been consistent since 2023. Rust changes of a similar size need about 20% fewer revisions than their C++ counterparts.

I read that as "code submitted for review has fewer issues to begin with".

That would certainly mirror my own subjective experience of coding in Rust: once I get the compiler to accept my code (which takes longer than in C++ sometimes), it usually works correctly on the first try, or only has some trivial logic bug ("oops, I forgot to actually write out the result to a file").

My educated guess as to why this is, is that some of the non-memory safety features of Rust help: in particular sum types and linear types (well, affine types really).

Sum types is "enums with payload" or "type checked tagged unions" for those who come from other programming languages.

Affine types is about functions transferring ownership of a value as a parameter in a function call. You can no longer use it after that.

Both of these together allow designing APIs that are harder to use incorrectly. Sum types by making it impossible to represent invalid state. Affine types help in many ways, such as making it possible to statically represent the state of an object in the code ("if I'm here in the code I know statically that the object must be in this state, and only then am I able to call this function on it")

One example of the latter is in embedded Rust where it is used for configuring GPIO pins: you have to fully configure the pin before the methods for writing/reading are exposed, and only those methods that are compatible with the configuration are available. Ownership is here also used to ensure two different parts of the code can't use the same pin in conflicting ways.

Code Review

Posted Nov 14, 2025 11:02 UTC (Fri) by bredelings (subscriber, #53082) [Link] (9 responses)

> That would certainly mirror my own subjective experience of coding in Rust: once I get the compiler to accept my code (which takes longer than in C++ sometimes), it usually works correctly on the first try, or only has some trivial logic bug ("oops, I forgot to actually write out the result to a file").
>
> My educated guess as to why this is, is that some of the non-memory safety features of Rust help: in particular sum types and linear types (well, affine types really).

Yes, people say the same thing about Haskell -- once you fix all the compile errors it often works the first time. And Rust and Haskell have very similar type systems.

Code Review

Posted Nov 14, 2025 16:38 UTC (Fri) by develop7 (guest, #75021) [Link] (8 responses)

This is precisely my first ever Haskell open-source contribution experience: locate where and what to change (with grep), change stuff the way you need it to be, address all the compilation errors, get a working binary, see it works flawlessly first time, submit a PR, prepare for major refactoring suggestions, get accepted after minor changes, mind blown because it was never a thing in my 15 previous years in software development.

7 years later, it works that way in ~80% of cases, way more often than it ever was with mainstream.

Code Review

Posted Nov 14, 2025 18:43 UTC (Fri) by Vorpal (guest, #136011) [Link] (7 responses)

Interesting. I dabbled in Haskell many years ago, but I lost interest somewhere between monads and applicative functors (I think that was the name). Haskell was too much abstract math for me.

Pure math is not my thing. I'm far more towards the applied side of things, if I can't see a concrete use case for it, my eyes glaze over.

Rust hits that sweet spot: built on fancy math, but unless you are literally working on the compiler itself you don't need to engage with the theory behind it.

Code Review

Posted Nov 14, 2025 19:22 UTC (Fri) by tialaramex (subscriber, #21167) [Link] (2 responses)

Even inside the compiler, only a relatively small portion needs you to understand any deep theory of program transformation. A lot of the Rust compiler is either turning a correct Rust program text into abstract syntax, or diagnosing some mistake which rendered your input not a correct Rust program in the way most likely to result in you going:

"Oh! Yeah, that's wrong, I will fix it"

and rarely that you say instead:

"Stupid compiler. It's not wrong, either shut up and accept what I wrote or explain clearly the problem"

I had a Rust diagnostic that I felt was less helpful than it should be. I grep'd the error text, found a constant with that text as its definition (this is all memory so details may be wrong) and then found that constant used only once, at the site emitting the diagnostic text. I read surrounding code and intuited how to write a better diagnostic, and yeah, first time it compiled it actually worked - as I got more familiar with the surrounding code I actually added some useful extra stuff until I was happy that anyone seeing this diagnostic was getting the best I could give them. One thing I realized part way through is that we're not on the happy path - nobody is ever going to curse that my diagnosis code is inefficient, because their program is wrong, and I'm telling them why, if the program wasn't wrong my code never runs at all. From "How hard can it be?" to a (nightly) release with my fix took less than one week. Rustc's reviewer was very helpful in shepherding me through and identifying anywhere my change did need small improvements to hit their quality goals.

Non-technical advantages of rustc

Posted Nov 15, 2025 10:37 UTC (Sat) by farnz (subscriber, #17727) [Link] (1 responses)

Your comment about improving a diagnostic brings up one thing that the rustc project gets right, and that helps Rust's adoption; diagnostics (both lints and failures) are continuously being improved, and the people behind the compiler are supportive of efforts to make the diagnostics better.

This sort of work isn't always seen as valuable - after all, an error like "problem in type unification: cannot meet constraints for arg, arg is parameterized type T, T is required to implement Debug + Send + Sync, but supplied value param has type MyParamType, which implements Display + Send + Sync + Unpin + RefUnwindSafe + UnwindSafe" contains all the information you could possibly need to diagnose the bug, but "param is of type MyParamType, which does not implement Debug, which is required in funct(param) by fn funct<T: Debug>(arg: T)" is so much more helpful to the user, even though it has strictly less information than the first form.

Non-technical advantages of rustc

Posted Nov 16, 2025 2:37 UTC (Sun) by tialaramex (subscriber, #21167) [Link]

AIUI One of the things which consciously drove that, and which is as often a source of conflict on LWN as the claims of improved correctness, is Rust's tag line: "A language empowering everyone to build reliable and efficient software"

Because we're not "empowering everyone" if we've made it easy for you to attend our conference but practically impossible to understand our compiler warnings.

Seeing this tag line from other angles also encourages other technical changes, for example Rust often goes out of its way to have the obvious thing you'd write be efficient rather than try to teach Rust programmers to write something else that is already efficient - for beginners this means it's more likely that the Rust program you wrote, though perhaps not very sophisticated, has excellent performance anyway, but even for experienced Rust programmers it means often you don't need to figure out a clever way to write what you meant efficiently, the obvious way to write it is optimised anyway.

Code Review

Posted Nov 15, 2025 15:04 UTC (Sat) by develop7 (guest, #75021) [Link] (2 responses)

> I lost interest somewhere between monads and applicative functors (I think that was the name). Haskell was too much abstract math for me.

I've been there too! But that time I've decided to try skipping things that don't click yet and just "fix the darn thing" instead and that worked way, way better than I've expected. That's what I call programming in an _actually_ high-level programming language.

Monads-wise, here's a simple explanation why we _all_ need them: https://philipnilsson.github.io/Badness10k/escaping-hell-...

> Pure math is not my thing. I'm far more towards the applied side of things, if I can't see a concrete use case for it, my eyes glaze over.

Makes two of us, but Haskell is not about pure math — our monads are more like a pattern, typechecked by a compiler. If anything it is most down-to-earth lazy functional programming language.

Code Review

Posted Nov 17, 2025 8:55 UTC (Mon) by taladar (subscriber, #68407) [Link] (1 responses)

The biggest thing that I took away from using Haskell for a few years is that abstract code is actually a lot simpler to reason about than code with concrete types.

That is because abstract code makes it explicit which operations you are allowed to perform on the values you operate on which means this set is much, much more constrained than the operations you could perform on any given concrete type. In particular the absence of a way to create arbitrary new values of a type usually makes reasoning a lot easier because every value of the type you return must originate with a value you pass into the code.

Code Review

Posted Dec 13, 2025 9:20 UTC (Sat) by Chousuke (subscriber, #54562) [Link]

That's actually mathematically provable, to a point. The more abstract a (pure) function type is, the fewer possible implementations it has.

For the simplest example, there's only one function with the type a -> a.

Code Review

Posted Nov 19, 2025 19:59 UTC (Wed) by donbarry (guest, #10485) [Link]

From Edsger Dijkstra's "How do we tell truths that might hurt?" list of programming truths:

"Programming is one of the most difficult branches of applied mathematics; the poorer mathematicians had better remain pure mathematicians."

Code Review

Posted Nov 14, 2025 19:41 UTC (Fri) by tialaramex (subscriber, #21167) [Link] (1 responses)

For Sum Types in particular I think the type theoretical name (Sum types) is better than referring to ideas like "tagged unions" because Rust is quite aggressively (and likely to be even more aggressive in future) optimising these types.

A tagged union type can feel like it has to be slower, the naive C implementation of Option<OwnedFd> would be bigger and slower than C's int file descriptors because it would need to store that separate tag value. In fact rust's Option<OwnedFd> is mechanically indistinguishable from just a C file descriptor at runtime because a valid file descriptor can't be -1, so the -1 bit pattern is used for None while all the other file descriptors Some(fd) are stored as the bit pattern for their integer value. Correct C and Rust ends up with basically the same machine code, but the type system means it is more likely that the compiler will catch your inevitable mistakes in Rust.

Linear types would be very cool, but alas Rust doesn't have them. The Affine types, which Rust has, mean that you can't accidentally refer to a Goose after it no longer exists, and thus you also can't "double free" it, because it's gone. But the Linear types additionally ensure you must free the Goose, whereas Affine types aren't bothered if you forget. The fallout from that was the Leakpocalypse of fame slightly before Rust 1.0 and corresponding choice to mark Box::leak safe because these are affine types -- people *can* safely leak the Box even if you tell them not to so marking Box::leak unsafe would be a futile gesture.

Code Review

Posted Nov 15, 2025 7:21 UTC (Sat) by edomaur (subscriber, #14520) [Link]

There is that "Linear<T>" thingy from the linear_type crate but I'm not exactly sure it's stable/usable enough...

Code Review

Posted Nov 13, 2025 21:48 UTC (Thu) by rgmoore (✭ supporter ✭, #75) [Link]

Given that they also find a lower rollback rate, it sounds like the review goes faster because the code is easier to review. They say there's a big overlap between the coders working in C++ and Rust, so it would be odd if the same people were applying different reviewing standards depending on the language.

Code Review

Posted Nov 13, 2025 23:52 UTC (Thu) by khim (subscriber, #9252) [Link] (4 responses)

It absolutely is a good thing. Remember that they are comparing Rust to C and C++, not to Java or Python.

Core reviewers are very through in Google and catch lots of memory safety bugs before fuzzers may do that… but that takes time.

Rust compiler does it much faster and automatically.

Of course you are still left with many issues that are more stylistic, but the lack of cognitive load from constantly rechecking object liveness story in your head is a big deal.

Code Review

Posted Nov 14, 2025 9:45 UTC (Fri) by taladar (subscriber, #68407) [Link] (2 responses)

If you establish a process that includes running clippy and cargo fmt before commit stylistic issues can also focus on higher level things.

Code Review

Posted Nov 14, 2025 10:11 UTC (Fri) by hailfinger (subscriber, #76962) [Link]

Reducing cognitive load by removing complete classes of errors does help a lot. This way, I can focus attention on the things which can still go wrong.
Whenever I do code review of C code and perform a re-review of fixed code, I have to recheck all the memory safety aspects again. Even if I'm sure memory safety is OK in the current iteration, I cannot banish thinking about memory safety while focusing on other code correctness aspects.
A similar mechanism is in play for stylistic issues. Let the tools take care of it as much as possible.

Any memory-safe language helps reduce cognitive load during code writing and code review, and with Rust we seem to have a contender which is fast enough and popular enough to stay.

Code Review

Posted Nov 14, 2025 11:26 UTC (Fri) by khim (subscriber, #9252) [Link]

Sure, but we are talking Android here. Means style guide, clang-format and clang-tidy.

Rust may still have a small advantage there, but not huge. But the lack of need to think about lifetimes during code review (that happens before you send you change to reviewer) is huge.

Code Review

Posted Nov 16, 2025 14:22 UTC (Sun) by cceckman (subscriber, #134382) [Link]

Yes, this, exactly.

I used to write and review C++ code at Google (not Android, but also firmware/driver stuff). I *consciously* did the work that the Rust language and borrow-checker do: associating pointers with allocation lifetimes, tracking ownership and mutability, etc. (C++11 helped a lot with this, but not fully; still a lot of raw pointers.)

Even when the code was correct, getting to the point where I *believed* it was correct took a lot of time and energy.

1000x dubious

Posted Nov 14, 2025 10:02 UTC (Fri) by randomguy3 (subscriber, #71063) [Link] (85 responses)

Having read the article, this seems overall very positive, and some great empirical data about the value of memory safe languages. I think the specific "1000x reduction in memory safety vulnerability density" claim is rather suspect though.

There is clearly a large reduction, but this number is based on a sample size of one on the rust side. It could easily be out by an order of magnitude (in either direction), just by random chance.

1000x dubious

Posted Nov 14, 2025 11:02 UTC (Fri) by hunger (subscriber, #36242) [Link]

I am impressed by any systems programming language, where the first memory safety issue is found years after introducing the language.

I do not mind the specific numbers.

1000x dubious

Posted Nov 14, 2025 11:39 UTC (Fri) by aszs (subscriber, #50252) [Link]

"With roughly 5 million lines of Rust in the Android platform and one potential memory safety vulnerability found (and fixed pre-release), our estimated vulnerability density for Rust is 0.2 vuln per 1 million lines (MLOC)." [over a period of 5 years]
I didn't see any assertions about the precision of the 1000x claim in the post so not sure why that's dubious? When would you feel comfortable with it? 4 vuln in 20 million lines of code? 20 in 100 million?

1000x dubious

Posted Nov 14, 2025 13:26 UTC (Fri) by mbunkus (subscriber, #87248) [Link]

I generally agree, but it's not just about the number of bugs, but also about the time & LOCs. If, for example, they do the same kind of report in ten years with 100× the amount of Rust code but still only at one bug, they'd be well justified to use such a number.

Personally I appreciate they only used 1,000 instead of 5,000 which they could have used just as well (0.2 vuln per 1 MLOC vs 1,000 vuln per 1 MLOC is a factor of 5,000 if you take those numbers verbatim).

1000x dubious

Posted Nov 14, 2025 18:37 UTC (Fri) by Vorpal (guest, #136011) [Link] (2 responses)

The point about lack of statistical rigor is fair, and unfortunately all to common in comp sci in general in my experience. Compared to medical or physics studies, even peer reviewed compsci papers are often very lacking in this area.

However, regardless if the true ratio is 100x or 10000x or somewhere within that span, it seems fairly certain it is *far* better than the situation in C or C++ code.

My personal main reason for coding in Rust though is not the reduced number of bugs (though that certainly helps). The main reason for me is that it making programming fun again.

1000x dubious

Posted Nov 14, 2025 20:54 UTC (Fri) by excors (subscriber, #95769) [Link]

It does seem statistically valid, from what I vaguely remember of statistics. They say C++ has an error rate of 1e-3 (per LOC), and Rust has an error rate at least 1000x better, i.e. better than 1e-6. Assuming a binomial distribution with N=5e6 and p=1e-6, that gives a 96% probability of getting > 1 error in a 5MLOC sample of Rust.

They observed exactly 1 error, which is unlikely (to a statistically significant level) under that assumed 1e-6 error rate, so it's fair to reject the null hypothesis that the error rate is exactly 1e-6 and therefore claim it's actually better than 1e-6 (which is precisely what they say).

They couldn't make the same claim for e.g. 0.5e-6, because their observation would no longer be statistically significant. So their actual claim is the best it can be.

Since they don't show their working, maybe they just picked "1000x" because it sounded like a nice round number, but it does coincide with that slightly more rigorous analysis. (...assuming I've calculated it correctly)

1000x dubious

Posted Nov 14, 2025 23:58 UTC (Fri) by Wol (subscriber, #4433) [Link]

> The point about lack of statistical rigor is fair, and unfortunately all to common in comp sci in general in my experience. Compared to medical or physics studies, even peer reviewed compsci papers are often very lacking in this area.

Due in part to the attitude (actually common across a lot more than comp sci) of dismissing personal experience as "mere anecdotes".

I'm not saying those experiences are correct, but they are data points. And they need to be explained. If you don't at least take someone else's personal experiences seriously, you are living confirmation bias in action. If you don't believe it, you need to explain it away.

Which is why, if you go back over my database debates, I've always tried to argue in terms of facts (as in observed states), logic and maths. Not always successfully I expect, but who always is?

(But bear in mind, comp sci is - imho - much more maths than science. As such, statistical rigour is far less important. You use stats to tie observation and theory together, and given that comp sci is much more theory than observation, where's the need for stats?)

Cheers,
Wol

1000x dubious

Posted Nov 14, 2025 19:36 UTC (Fri) by tialaramex (subscriber, #21167) [Link] (78 responses)

Regardless of the exact numbers, this entire ballpark is clearly "Silver bullet" territory. Brooks characterises silver bullets as order of magnitude improvements to e.g. reliability and this as I understand it would qualify.

Brooks describes the high level programming languages (which as I understand includes C, rather than only meaning things like Python as some commentators might today) as having achieved that silver bullet improvement, and at the time he first wrote he doubts that Ada will fulfil a promise of a further such order of magnitude, I would say he was correct, but that perhaps in some sense Rust is making good on that.

More generally outside software engineering a "silver bullet" is generally associated with a full blown panacea, rather than merely an order of magnitude improvement, but in programming certainly people associate it with Brooks' paper and so with the order of magnitude not a fanciful arbitrarily larger improvement.

1000x dubious

Posted Nov 15, 2025 9:21 UTC (Sat) by cyperpunks (subscriber, #39406) [Link] (77 responses)

Note that the sole bug found was in unsafe block, exactly as one would assume, while everything in C/C++ is unsafe by definition (as rust define it).

The time for new development in C/C++ is over, so the real question should be why have they don't converted even more
of Android to rust (or other memory safe languages)?

What will Google do to remove those barriers so Android can be truely safe?

1000x dubious

Posted Nov 15, 2025 16:37 UTC (Sat) by khim (subscriber, #9252) [Link]

> The time for new development in C/C++ is over, so the real question should be why have they don't converted even more of Android to rust (or other memory safe languages)?

Because they couldn't. It's really hard to convert any C++ program to Rust piecemeal, you need to rewrite it in one go.

That effort is hard to justify. But that happened before, in the end of last century, when people switched from Pascal and Basic to C, Java and C#, it may happen again.

> What will Google do to remove those barriers so Android can be truely safe?

Current bet is Crubit, but it's still not production ready.

P.S. Going from C to Rust is much easier but LWN articles show that kernel people have trouble even with that… give it time.

Memory-safe C code

Posted Nov 15, 2025 23:08 UTC (Sat) by alx.manpages (subscriber, #145117) [Link] (75 responses)

> while everything in C/C++ is unsafe by definition (as rust define it).

I don't think that's true. Not even with Rust's definition of memory safety.

It's possible to write memory safe APIs in C. It needs macro trickery, and combinations of modern language features.

The main difference with Rust is that you need to opt-in to safety, instead of opting out of it. Also, there's no 'unsafe' keyword that distinguishes such code from the surroundings. However, once your code base does extensive use of these APIs, you essentially get a safe program.

To be fair, the kind of safety you can guarantee in C is only spatial (bounds safety). Use-after-free bugs are still possible, even if less likely.

Memory-safe C code

Posted Nov 16, 2025 0:26 UTC (Sun) by excors (subscriber, #95769) [Link] (43 responses)

>> while everything in C/C++ is unsafe by definition (as rust define it).

> It's possible to write memory safe APIs in C. It needs macro trickery, and combinations of modern language features.
>
> The main difference with Rust is that you need to opt-in to safety, instead of opting out of it. Also, there's no 'unsafe' keyword that distinguishes such code from the surroundings. However, once your code base does extensive use of these APIs, you essentially get a safe program.

That sounds exactly like what Rust calls unsafe. You could add the `unsafe` keyword to every function in your Rust program and then be careful to never call an "unsound" API (i.e. one that can actually trigger undefined behaviour when executed), and never do operations like pointer dereferencing that can trigger UB, and you'd be in the same situation as C code that only uses "memory safe APIs".

"Safe" in Rust basically means "the compiler can prove this won't trigger UB", and "unsafe" means "this won't trigger UB, and the compiler will believe that even if it can't prove it". (I think it helps to read "unsafe" as an abbreviation of "unprovably safe", not as a synonym for "dangerous"). The important distinction between safe and unsafe is the proof. C compilers don't do the proof, so C is always (in Rust's terminology) unsafe, no matter how well designed your APIs are.

Memory-safe C code

Posted Nov 16, 2025 6:52 UTC (Sun) by alx.manpages (subscriber, #145117) [Link] (42 responses)

> You could add the `unsafe` keyword to every function in your Rust program and then be careful to never call an "unsound" API (i.e. one that can actually trigger undefined behaviour when executed), and never do operations like pointer dereferencing that can trigger UB, and you'd be in the same situation as C code that only uses "memory safe APIs".

> C compilers don't do the proof

C compilers do more than that. At least if you use a long list of -Werror=... flags.

We need some more of those, I agree, but it does proof, to some extent. You need to opt in to those errors.

You can write C code where you know the compiler will prove you won't trigger most cases of UB.

I'm working specifically on a GCC patch with which you can write C functions where the compiler can prove you won't do any buffer overflows.

Memory-safe C code

Posted Nov 16, 2025 17:30 UTC (Sun) by khim (subscriber, #9252) [Link] (41 responses)

> it does proof, to some extent

It's like saying that someone is “pregnant, to some extent”. You either do proof or you don't do it. And C/C++ don't do it. Period.

> You can write C code where you know the compiler will prove you won't trigger most cases of UB.

Yes, but you can not teach compiler to reject code that triggers UB. That's fundamental difference.

> I'm working specifically on a GCC patch with which you can write C functions where the compiler can prove you won't do any buffer overflows.

That's nice, but the problem with that approach is that, in the end of the road, you wouldn't have C, you would have some other language that can be compiled with C compiler.

If such thing would have been created 20 or even 10 years ago it would have been very interesting, but today… Rust already exist.

Memory-safe C code

Posted Nov 16, 2025 17:46 UTC (Sun) by alx.manpages (subscriber, #145117) [Link] (9 responses)

> It's like saying that someone is “pregnant, to some extent”. You either do proof or you don't do it. And C/C++ don't do it. Period.

That's too simplistic. It's possible to prove that certain bugs can't happen, even if you can't prove others. And there's work for improving the cases where it can't.

> Yes, but you can not teach compiler to reject code that triggers UB. That's fundamental difference.

I don't think I understand you. Here, I'm teaching the compiler to reject code that triggers UB, by passing -Werror=overflow:

alx@devuan:~/tmp$ cat ub.c
#include <limits.h>

int
main(void)
{
return INT_MAX + 1;
}
alx@devuan:~/tmp$ gcc -Werror=overflow ub.c
ub.c: In function ‘main’:
ub.c:6:24: error: integer overflow in expression of type ‘int’ results in ‘-2147483648’ [-Werror=overflow]
6 | return INT_MAX + 1;
| ^
cc1: some warnings being treated as errors

Please clarify if you mean something else.

> That's nice, but the problem with that approach is that, in the end of the road, you wouldn't have C, you would have some other language that can be compiled with C compiler.

What's C? K&R C? C89? C99? C11? C23? GNU C? There's no such thing as a pure C language. There are dialects; there have always been dialects. Some dialects are safer than others. Depending on the flags you pass to your compiler, you're creating your own dialect.

> If such thing would have been created 20 or even 10 years ago it would have been very interesting, but today… Rust already exist.

Improving existing C code to be safe is much easier than rewriting the world. Rust still doesn't exist, in a way.

Memory-safe C code

Posted Nov 16, 2025 17:58 UTC (Sun) by khim (subscriber, #9252) [Link] (8 responses)

> It's possible to prove that certain bugs can't happen, even if you can't prove others. And there's work for improving the cases where it can't.

This road leads to Zig, not to Rust.

> Here, I'm teaching the compiler to reject code that triggers UB, by passing -Werror=overflow

Yes, you are removing one, pretty minor UB. That's commendable, but not the point of safe languages. The main idea behind Java, C# and most other modern languages is that they can be explored “by poking”: if there are no UB and no “nasal daemons” then problems in your code can be investigated and, eventually, fixed. All critical bugs that are very hard to detect and fix live in the TCB (runtime for most language, in these 4% pieces of unsafe in Rust).

But if UB can exist anywhere in your code then everything in your code is TCB.

> Improving existing C code to be safe is much easier than rewriting the world. Rust still doesn't exist, in a way.

I would believe it when I'll see it. Because I hear that mantra for about 20 years. Rust conceived and released in that time… C/C++ still have awful problems, even today.

I wish you luck, I'm just not sure if you would be able to do anything, the main problems of C are not technical, they are social: the fact that C have so many UBs is the minor (and fixable) issue, surprisingly enough, the main issue is that many C developers simply don't believe they need to avoid UB. At all.

Making UB visible in your code (like Rust did) is nice solution. Not sure you can add anything else while staying in C.

Memory-safe C code

Posted Nov 16, 2025 18:30 UTC (Sun) by alx.manpages (subscriber, #145117) [Link] (7 responses)

> Yes, you are removing one, pretty minor UB.

That was a trivial counterexample. My actual build flags have more than a hundred -Werror= flags, removing not-just-one UB.

What if you could have a -Werror=any-buffer-overflows that would catch any possible buffer overflows? That wouldn't be minor, and we're not far from such a thing in C. The main part of this, I'd like to merge it for GCC 17. Then, there would be some more work needed to make it perfectly safe, but with that part, you could already write much better code.

>> Improving existing C code to be safe is much easier than rewriting the world. Rust still doesn't exist, in a way.

> I would believe it when I'll see it.

All of the improvements I'm researching, I'm applying them to the shadow-utils project. I've already removed many classes of bugs there. The code base is so clean (except in some parts I haven't touched yet), that you can work on it like you'd do in Rust: write some code, iterate until it builds, and once it builds, it should work. Soon, the possibility of buffer overflows in that project will be part of the past. I'd be already surprised if one was found in most parts of it, even if it's theoretically still possible.

> I wish you luck, I'm just not sure if you would be able to do anything, the main problems of C are not technical, they are social

Yup, that's part of the problem. I'm thankful that Rust has done the job of convincing the world that safety is important, and more importantly, feasible. If some projects migrate their C code to more modern dialects, that would be an improvement, even if some code bases are more reticent to that.

> Not sure you can add anything else while staying in C.

A compiler rejecting buffer overflows would also reject much existing code (false positives). However, rewriting the code to appease the compiler would be trivial, and using syntax natural to C programmers. I'm not too worried about that part. You'd change for example pointer syntax to array syntax. Some programmers might reject the idea, but I believe most would accept it, if that brings buffer overflows to an end.

Memory-safe C code

Posted Nov 16, 2025 18:37 UTC (Sun) by khim (subscriber, #9252) [Link] (6 responses)

> That wouldn't be minor, and we're not far from such a thing in C.

Anything that doesn't handle memory allocations would be “a minor thing”. That's why Ada was such a big thing in some [limited] places (like embedded firmware) and ho-hum event in the majority of places: when you may live without dynamic memory allocations Ada works great, where you couldn't… it's not much better than C. At least that's how it worked for a few decades.

It eventually got pointers handled (by borrowing ideas from Rust, of course), but at this point it was too late.

> Then, there would be some more work needed to make it perfectly safe, but with that part, you could already write much better code.

That would be a good thing, definitely… but to achieve similar reduction in the bug rate you need to handle memory allocations, somehow.

That's the biggest problem and biggest pay-off.

Memory-safe C code

Posted Nov 16, 2025 19:36 UTC (Sun) by alx.manpages (subscriber, #145117) [Link] (5 responses)

> Anything that doesn't handle memory allocations would be “a minor thing”.

Agree. Why did you assume it wouldn't handle memory allocations? :-)

When I said any buffer overflows, I actually meant it. No buffer overflows even in malloc(3)'d memory.

> That would be a good thing, definitely… but to achieve similar reduction in the bug rate you need to handle memory allocations, somehow.
>
> That's the biggest problem and biggest pay-off.

Yup.

Memory-safe C code

Posted Nov 16, 2025 20:26 UTC (Sun) by khim (subscriber, #9252) [Link] (4 responses)

> Agree. Why did you assume it wouldn't handle memory allocations? :-)

Because these are, essentially, impossible to track without extra viral markup everywhere. Even a simple call to strstr leaves you with a dilemma of validness of returned pointer (is its validity tied to needle or to haystack?) and, as an added bonus, it also gives you a write access to the buffer than sometimes could and sometimes couldn't be modified.

These problems are not impossible to track… but getting people to add (and correctly add!) such markup sounds like a more-or-less impossible thing to do.

Essentially: it's hard but possible to add all these things to the language. But after you'll do that you'll need to rewrite almost everything anyway… and if you are doing it why not pick a nicer, more modern, language?

Memory-safe C code

Posted Nov 16, 2025 20:48 UTC (Sun) by alx.manpages (subscriber, #145117) [Link] (3 responses)

> [strstr] gives you a write access to the buffer than sometimes could and sometimes couldn't be modified.

That was solved already in C23. strstr(3) now returns QChar*, which is as qualified as the input.

<https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3220.pdf>

> Even a simple call to strstr leaves you with a dilemma of validness of returned pointer (is its validity tied to needle or to haystack?)

I don't understand what you mean by 'validness'. I assume you mean provenance?

If so, I agree that GCC should add an attribute such as [[gnu::returns_derived_ptr()]], which would add that information to the API. There exist similar attributes already, so this wouldn't be very difficult.

[[gnu::returns_derived_ptr(1)]]
[[gnu::null_terminated_string_arg(1)]]
[[gnu::null_terminated_string_arg(2)]]
char *strstr(const char *haystack, const char *needle);

> Because these are, essentially, impossible to track without extra viral markup everywhere.

Yes, the attribute would fall under that "viral markup". libc is already full of those things. And I also use many of them in my own code.

> These problems are not impossible to track… but getting people to add (and correctly add!) such markup sounds like a more-or-less impossible thing to do.

If you show them a C code base that is as safe as Rust in terms of buffer overflows, and adding some attributes in some function prototypes is the only thing that needs to be done, I hope some programmers can be convinced.

About doing it correctly, the compiler should be able to tell if it's wrong when seeing the implementation. If the pointer isn't derived from the first argument in some path, it would of course diagnose.

> Essentially: it's hard but possible to add all these things to the language. But after you'll do that you'll need to rewrite almost everything anyway… and if you are doing it why not pick a nicer, more modern, language?

There's a difference between adding attributes to function prototypes and entirely rewriting the code.
These improvements can be done piecemeal, verifying that each change is self-correct, resulting in minimal logic bugs in the rewrite, compared to writing from scratch.

Memory-safe C code

Posted Nov 16, 2025 21:22 UTC (Sun) by khim (subscriber, #9252) [Link] (2 responses)

> I don't understand what you mean by 'validness'. I assume you mean provenance?

I mean: how would your compiler know whether to accept the program or reject it. Rust uses lifetimes for that and that use, in turn, means that it needs to mark them on all the functions that return references and then on structures that may carry references and then on pointers to functions (because now function that receives pointer to first element and function that returns pointer to the second element are different) then you need borrow checker and so on.

It's huuuuge can of worms to do that properly.

> If so, I agree that GCC should add an attribute such as [[gnu::returns_derived_ptr()]], which would add that information to the API. There exist similar attributes already, so this wouldn't be very difficult.

Bwahaha. Try it and you'll find hundreds of use-cases that seem “natural” yet are rejected by a naïve validator.

Or, better yet, you may read papers that describe these things. You'll need borrows, reborrows, split borrows and bazillion other things to make it ergonomic. And then, after all that… you would still need to rewrite all code to ensure that complies with these rules.

You would probably need to spend 5 to 10 years to just plug all the loopholes in your typesystem… and “let's rewrite it in Rust” guys wouldn't wait all that time thumbing their fingers.

> That was solved already in C23. strstr(3) now returns QChar*, which is as qualified as the input.

Typical story of disruptive technology: it's really nice to know that C have done first two steps (out of hundred) needed to achieve memory safety… but would anyone still care 10 (or 20 or 30…) years down the road when it would finally traverse it and provide something that actually works? We would see, but past history is not encouraging.

It's like Bucyrus: it understood that hydraulics is the future very early, tried to build something that his customers would buy for half century… but their customers had no need for underpowered hydroshovel and the ones who needed it knew hydroshovels are made by Caterpillar, not by Bucyrus… thus the whole thing ended with Caterpillar buying them, after half-century. Similarly here: even if after 5-10-20-30 years all that stuff would be finished… you'll find no users for it: people who are willing and capable of rewriting things would be using Rust by then, and the remaining guys would continue to use C-as-it-exist-today, because they just don't want or couldn't rewrite everything.

> If you show them a C code base that is as safe as Rust in terms of buffer overflows, and adding some attributes in some function prototypes is the only thing that needs to be done

Nope, that's precisely the issue: that's just a tiny part of “what needs to be done”. Even such a simple structure as a doubly-linked list is more-or-less impossible to describe in these terms. Rust solution is to give you an unsafe-based LinkedList that you are supposed to use in place of your ad-hoc lists.

For many C codebases this would imply more-or-less total rewrite.

> There's a difference between adding attributes to function prototypes and entirely rewriting the code.

Yes. And for small, really small percentage of C code the former approach may work. For the majority the latter is strict requirement. As in: more-or-less full rewrite. Because too many data structures couldn't be handled with a markup. And to ensure that you code is safe you need small amount of well-designed and tested implementations used by everything… which is precisely the worst side of C/C++ in practice: practically everyone creates their own ad-hoc data structures instead of reusing them.

Worse yet: benefits for the codebases that belong to the latter category (just add markup and everything works) is negligible (they, usually, don't have any memory bugs to begin with because if lifetime story is so simple that you can trivially describe to the compiler then you can describe it to the fellow developer, too), while for codebases where you really want to make it approach work (because they have very complicate story about liveness of the variables in their codebase) you need a rewrite.

So your improvements to C would benefit projects that barely need them yet would leave unfixed bugs in complicated codebases that suffer from memory unsafety worst.

Memory-safe C code

Posted Nov 18, 2025 0:23 UTC (Tue) by alx.manpages (subscriber, #145117) [Link] (1 responses)

> Bwahaha.

Please, moderate yourself. This is quite inappropriate.

Memory-safe C code

Posted Nov 18, 2025 0:45 UTC (Tue) by khim (subscriber, #9252) [Link]

Well… you are proposing to add something that took more than a decade of development, that both including people with PhD and was deemed novel enough and complicated enough to warrant new PhD and professor's position in a prestigious college and you call all that some more work needed to make it perfectly safe?

I honestly don't know whether to laugh at naïvety or applaud the audacity… developing rules that would be both airtight and ergonomic to use is hard… and given the fact that you still need to rewrite more-or-less all the code after you'll do it… adoption would be EVEN HARDER.

Don't get me wrong: if you would manage to retrofit enough markup in C to make it memory safe and then manage to convince people to actually adopt the result (the harder part)… it would be huge achievement, gigantic achievement, awe-worthy achievement, but… I don't hold my breath. Chances of that happening are almost zero.

Memory-safe C code

Posted Nov 16, 2025 17:49 UTC (Sun) by mb (subscriber, #50428) [Link] (21 responses)

I think we need a combination of everything.

- Improve current compilers and checker tools to catch more cases while keeping the required changes to the code low. This will never bring C safety anywhere near that of safe languages, but it will definitely make it safer.
- Write new code in safe languages only.
- Compile existing code with tools like Fil-C, if performance is less of an issue.
- Rewrite critical parts that directly interact with untrusted data (e.g. complex parsers) in safe languages.

All of this is currently being done or being experimented with.
And I think we need *all* of these things to improve the over all situation without going to unrealistic scenarios like "Rewrite everything in Rust".

Memory-safe C code

Posted Nov 16, 2025 18:03 UTC (Sun) by khim (subscriber, #9252) [Link] (20 responses)

> And I think we need *all* of these things to improve the over all situation without going to unrealistic scenarios like "Rewrite everything in Rust".

It's only unrealistic if you try to push it. I'm pretty sure eventually everything would rewritten Rust, but the trick is that if you would try to set a predetermined date when that should happen… people would find a way to fail to upgrade. Just think about the fate of Flash, specifically about The China-specific variant of Flash is still supported, by a company known as Zhongcheng.

Memory-safe C code

Posted Nov 16, 2025 19:50 UTC (Sun) by pizza (subscriber, #46) [Link] (19 responses)

> It's only unrealistic if you try to push it. I'm pretty sure eventually everything would rewritten Rust

...Just like all COBOL would be rewritten in something else, all FORTRAN would be rewritten in something else, etc etc?

Memory-safe C code

Posted Nov 16, 2025 19:55 UTC (Sun) by khim (subscriber, #9252) [Link]

More-or-less. COBOL and FORTRAN are stuck around because behemoths that used them initially are still with us — and, more importantly, behemoth that supports them, IBM, is still with us (and is accessible). With collapse of the unified world order IBM's support would become unavailable and then people would have to rewrite all that.

Rust seems well-poised for such rewrite but because we couldn't predict the exact timeframe of that process we don't know whether it would happen when Rust is the best candidate, or, perhaps, 10 years down the road when something even better would be invented.

But given where things are moving it doesn't look like we'll have 10 years.

Memory-safe C code

Posted Nov 17, 2025 12:11 UTC (Mon) by farnz (subscriber, #17727) [Link] (17 responses)

I think FORTRAN (and Fortran) are a good example of where things can go, yes.

Some people still use Fortran in niches where it's extremely productive, but then link it against other languages (I use, for example, a program that has a mix of Qt/C++ and Fortran, where the Fortran is doing some highly optimized number crunching, and the C++ is doing the UI and system interface).

Similarly, there's plenty of legacy FORTRAN out there that isn't going to get rewritten, because it does its job well, and it's been in use for long enough that all user-visible bugs have been fixed by now. Rewriting this would just risk introducing user-visible bugs for no benefit.

But outside those two categories (niche it excels in, legacy code), it's not really being used much. You'd not normally see a new project started in FORTRAN (or even Fortran 90 or later), and if parts of the code are problematic, they'll probably be replaced with code in a new language (Julia, Python with numpy, or others) instead of putting a lot of time and effort into fixing the FORTRAN codebase, but why expend effort for no gain?

Memory-safe C code

Posted Nov 17, 2025 15:22 UTC (Mon) by ballombe (subscriber, #9523) [Link] (2 responses)

There are new fortran projects created every days, to run on large MPI clusters.
python or julia are not an option there.

Memory-safe C code

Posted Nov 17, 2025 15:23 UTC (Mon) by farnz (subscriber, #17727) [Link]

That qualifies as a niche; large MPI clusters are not a common case, and it's a niche in which Fortran is extremely productive.

Memory-safe C code

Posted Nov 21, 2025 0:03 UTC (Fri) by tialaramex (subscriber, #21167) [Link]

So, it happens that the people who look after at least two of my country's big MPI clusters work upstairs from me and I sometimes have lunch with them. There are Fortran (and even FORTRAN) manuals on their bookshelf - but in fact none of their current team can write Fortran and as I understand it there's no call for that to change.

Thirty years ago, the people who looked after the distant ancestors of those clusters all knew Fortran, which is presumably why we have Fortran books. Twenty years ago, there were definitely still people in their team who knew Fortran. But they were getting old, and in those twenty years they're all gone.

I don't know Julia, but I can tell you that while you obviously shouldn't write the actual bit-banging code in Python there is indeed MPI Python, because if you're comfortable in Python you can write all your high level code that way, and a native library (written in C, Rust, or indeed in principle Fortran) does the bit-banging without you needing to understand how exactly that works.

Memory-safe C code

Posted Nov 18, 2025 8:25 UTC (Tue) by taladar (subscriber, #68407) [Link] (13 responses)

FORTRAN is maybe also not the best example in terms of legacy code bases because it is often used in purely mathematical areas that by their very nature don't change much. Code bases that deal with concerns more closely linked to a changing real world (e.g. regulation, evolving cryptographic algorithms or protocols, parsers of changing file formats or network protocols) would be less likely to be usable unchanged for long enough that people would consider them bug and maintenance free.

Memory-safe C code

Posted Nov 18, 2025 9:46 UTC (Tue) by anselm (subscriber, #2796) [Link] (12 responses)

Code bases that deal with concerns more closely linked to a changing real world (e.g. regulation, evolving cryptographic algorithms or protocols, parsers of changing file formats or network protocols) would be less likely to be usable unchanged for long enough that people would consider them bug and maintenance free.

This is why these days, COBOL programmers get to name their own salaries.

Memory-safe C code

Posted Nov 19, 2025 9:28 UTC (Wed) by taladar (subscriber, #68407) [Link] (11 responses)

Which is a good data point to indicate that the companies still using COBOL did wait too long rewriting their code in something else, especially considering that even those COBOL programmers are dying off now.

Memory-safe C code

Posted Nov 19, 2025 9:37 UTC (Wed) by Wol (subscriber, #4433) [Link] (10 responses)

Or that they're happy to pay megabucks to pinch existing Cobol guys, but too stingy to provide a career path to cross-train people into it.

I can understand computer guys being wary of "learning a dinosaur skill", but if it's treated as "just another language programmers are expected to know", and they don't find themselves exclusively on Cobol? Or they take people from other skills who want to get into that sort of thing, and train them up?

The problem, basically, is that Cobol is no longer "sexy", so people don't come into the workforce knowing it ...

Compared to Fortran, programming is a side-line for scientists, and if a scientist is told "learn Fortran" it's not viewed as a career-defining choice.

Cheers,
Wol

COBOL programmers

Posted Nov 19, 2025 9:55 UTC (Wed) by farnz (subscriber, #17727) [Link] (8 responses)

Nowadays, they pay to train people in COBOL because it is cheaper to train a new programmer to do COBOL well than it is to rewrite the code in a newer language. Most people I know who've gone this route paid off their mortgage, then learnt COBOL as a way to get a low-stress, decent pay job to take them into retirement, although there are a few who learnt it straight out of university as part of working for a contracting firm who does COBOL stuff.

COBOL programmers

Posted Nov 19, 2025 13:21 UTC (Wed) by nijhof (subscriber, #4034) [Link]

When I was a PhD student, 1990-something, I started applying for a Cobol job. A fellow student got rejected because he got all answers right on the test...

COBOL programmers

Posted Nov 20, 2025 9:27 UTC (Thu) by taladar (subscriber, #68407) [Link] (6 responses)

Not sure I would consider a job low-stress that involves exclusively work with legacy projects.

Working on legacy projects can be low stress *if* demand on you is low.

Posted Nov 20, 2025 9:49 UTC (Thu) by farnz (subscriber, #17727) [Link]

It's low-stress if you work directly for a company with a COBOL codebase, because the demands are small. The consultancies charge about the same for a month of COBOL work as it costs to employ a person for a year, and thus organisations that would otherwise have to pay for multiple months per year of consultancy time have a huge incentive to keep their in-house COBOL programmers happy.

As, by and large, the COBOL programmers are willing to accept lower salaries (because of the low stress) than similarly experienced programmers working in modern languages, it's obvious to the usual suspects for causing stress that the COBOL programmers should be left alone - there's lower-hanging fruit than the people who aren't the highest paid programmers, and who are responsible for business-critical systems.

COBOL programmers

Posted Nov 20, 2025 14:44 UTC (Thu) by mathstuf (subscriber, #69389) [Link]

I think there's a difference between working with perpetually legacy code rather than code that *becomes* legacy every 6 months. I think I would prefer the former given the choice between the two. Or, maybe, neither and instead decide to be outside more often ;D .

Legacy projects (was: COBOL programmers)

Posted Nov 20, 2025 15:33 UTC (Thu) by dskoll (subscriber, #1630) [Link] (3 responses)

My last job prior to retirement was working on a large legacy codebase that had some... interesting... architectural decisions and quite a lot of technical debt. I spent much of my time cleaning it up and getting rid of technical debt, as well as adding a few new features.

I really enjoyed it. There's something about my brain that enjoys reverse-engineering and cleaning up old code bases. Additionally, the job was pretty chill, my coworkers were great, and there were no crazy externally-imposed arbitrary deadlines. I felt that I ended my career on a high.

Legacy projects (was: COBOL programmers)

Posted Nov 21, 2025 10:12 UTC (Fri) by taladar (subscriber, #68407) [Link] (2 responses)

It sounds like a large part of that enjoyment was in actually being able to change the legacy code though, so it depends a bit on how hard the legacy project drives the idea that any code change beyond the absolute minimum necessary is bad because it might introduce new bugs.

Legacy projects (was: COBOL programmers)

Posted Nov 21, 2025 12:51 UTC (Fri) by Wol (subscriber, #4433) [Link]

I thoroughly enjoy that sort of work too.

A lot of it is cleaning up technical debt - getting rid of all those repeatedly-invented wheels, turning duplicated code into subroutines, writing utility subroutines/macros/programs to maximise code re-use, eliminating dead code, yadda yadda. Writing a retrospective specification !!!

And it's the pleasure of leaving the code in a much better state for the people who come after you.

Cheers,
Wol

Legacy projects (was: COBOL programmers)

Posted Nov 21, 2025 14:15 UTC (Fri) by farnz (subscriber, #17727) [Link]

In general, the places that employ in-house programmers are very happy for you to refactor the legacy code - they have a certain amount of necessary change they have to do each year (things like complying with new regulations, or fixing bugs that don't show up until you have an end date after 2050), and they want that necessary change to happen quickly.

They recognise that change carries a risk of bugs, but they also recognise that it's better to have a weekly small chance of a bug (whether caused by a refactor, or caused by a required change) than a bigger chance of a bug when a required change is made. And they're hopeful that, by getting test cases written for each bug found when refactoring is done, they'll eventually reach a point where the test suite is big enough to let them rewrite in a new language (Java, Python, Go, TypeScript, whatever) without hitting the same issues previous rewrites have had.

Memory-safe C code

Posted Nov 20, 2025 5:17 UTC (Thu) by rgmoore (✭ supporter ✭, #75) [Link]

Or that they're happy to pay megabucks to pinch existing Cobol guys, but too stingy to provide a career path to cross-train people into it.

Once hiring experienced COBOL programmers away from another company is an accepted strategy, it makes training your own people less viable. It's a general problem with loss of loyalty*. If you can get employees with the skills you need by hiring them away from someone else, there's way less incentive to train people in house. On the one hand, it's faster (and consequently probably cheaper in the short term) to hire someone who already has the skills than to train an existing employee. On the other hand, if a company trains someone in house, the trainee may get hired away as soon as they know enough to be productive in their new skill.

*And I mean that both ways. Companies have to be loyal to their employees if they want loyalty in return.

Memory-safe C code

Posted Nov 20, 2025 22:28 UTC (Thu) by anton (subscriber, #25547) [Link] (8 responses)

If such thing would have been created 20 or even 10 years ago it would have been very interesting
There were several C implementations that caught bounds violations presented at the poster session of PLDI 2002 (probably elsewhere, too, but I was involved in that poster session, so I remember that). They used fat pointers for that work. Somehow that did not catch on, but in recent years I have read about similar things, this time including protection against dangling pointers and double free, with even fatter pointers. I think there has been an LWN article about such an effort recently.

In 2006 I listened to a talk by George Necula, where he explained that one needs to go with the regular ABI in order to be accepted, so he presented an approach that allowed sticking with the regular ABI: Add some annotations about the code (e.g., that argc provides the upper bound of argv), and the bounds correctness will either be proven at compile time or checked at run-time. This sounded very interesting to me. This has been implemented in the Ivy/Deputy work. After the research project ended (AFAIK in 2009 or so), nobody productized this work, so apparently it was not "very interesting" to the C programmers at the time.

I still think it's saner to add some annotations to a C program than to rewrite it in Rust, but apparently there is some cultural hurdle that cannot be taken: Some programmers welcome the checking, but they don't program in C, not even in deputized C; other programmers program in C, but they are not interested in the features that Ivy/Deputy or the fat-pointer C implementations offer. And it seems to me that this is just as true now as it was 20 or 10 years ago.

Memory-safe C code

Posted Nov 21, 2025 10:18 UTC (Fri) by taladar (subscriber, #68407) [Link] (1 responses)

This is just a special case of a more general human behavior.

When there is something old and something new the people who are open to change move to the new thing while the people who really do not like change stay behind, over time increasing the ratio of anti-change people in the old thing.

You can see that in other areas too, e.g. when the major industry in a town dies, the people open to change move away and a decade or three later you have a population that will not vote for anyone who wants to change things for the better with realistic plans that require modifications to their way of life, they all just vote for the populists who promise to make everything the way it was before that industry died in some magical unspecified way.

Memory-safe C code

Posted Nov 21, 2025 12:24 UTC (Fri) by pizza (subscriber, #46) [Link]

> You can see that in other areas too, e.g. when the major industry in a town dies, the people open to change move away

That is *much* more complicated than merely being "open to change".

It's far more accurate to say "able to relocate", but even that's a gross simplification of the economics and risk factors involved.

As for the rest of what you wrote, that voting phonomena is more accurately attributed to *age* (and race, sigh) and plays out in urban and rural environments alike.

Memory-safe C code

Posted Nov 21, 2025 12:19 UTC (Fri) by khim (subscriber, #9252) [Link] (5 responses)

> There were several C implementations that caught bounds violations presented at the poster session of PLDI 2002 (probably elsewhere, too, but I was involved in that poster session, so I remember that).

I'm, mostly, ignoring bound violations here: these were implemented in ALGOL 68, more than half-century ago, why are they even wort talking about? There were actually dropped out when ALGOL ideas were adopted into BCPL to create C.

Their reintroduction is a welcome change, but not ground-breaking at all.

The interesting part, as I wrote many time, is memory safety and the associated tracking of pointer validity.

Sorry if I was unclear, but I wrote that more than once and couldn't repeat that in every message here.

> Somehow that did not catch on, but in recent years I have read about similar things, this time including protection against dangling pointers and double free, with even fatter pointers.

That's different from what we are discussing here, though: Rust does things in compile time, isn't it? For the C variant to be ground-breaking it needs that, too.

Of course C that may achieve safety with fatter pointers is nice thing, obviously… just not ground-breaking.

> After the research project ended (AFAIK in 2009 or so), nobody productized this work, so apparently it was not "very interesting" to the C programmers at the time.

Obviously. C programmers were secure in their knowledge that they are indispensable… only when Rust have grown to the point where there are more new Rust code in Android they started thinking about doing something. It's typical situation with disruptive innovations.

> I still think it's saner to add some annotations to a C program than to rewrite it in Rust, but apparently there is some cultural hurdle that cannot be taken: Some programmers welcome the checking, but they don't program in C, not even in deputized C; other programmers program in C, but they are not interested in the features that Ivy/Deputy or the fat-pointer C implementations offer. And it seems to me that this is just as true now as it was 20 or 10 years ago.

It's the same story with all disruptive innovations. Story, typically, happens like this:

  1. Year Y0: disruptive innovation happen, but couldn't be immediately adapted by users of “old tech” because there are lots of problems with it. Adoptions happens in the “new industry”, instead.
  2. Year Y0 + N: two things are happening:
    • “New teach” is improved enough to start being used in places where “old tech” is dominating.
    • “Old tech” developers wake up and start new project to bring “old tech” to the parity with “new tech”.
  3. Year Y0 + 2*N: two things are happening:
    • “New tech” is adopted by almost everyone (90% of developers either use it or would never adopt new innovations at all)
    • “Old tech” have grown to the point where it's on the parity with “new tech”… but nobody cares anymore.

See the problem? Disruption (and, often, destruction of “old tech”) happening not because it's not possible to extend the “old teach”, but because between stages #1 and #2 users of “old teach” are not interested (and thus technology is not developed and not adopted), while between stages #2 and #3 they are interested and they already have they way forward: adopt the “new teach”.

Here, with Rust:

  1. Year 2015: Rust appears, but have too many deficiencies to be used in all places where C is used — no inline assembler, borrow checker is extremely painful, etc.
  2. Year 2025:
    • Rust is growing like a weed.
    • C people take notice and start reforming C.
  3. Year 2035 (prediction):
    • Rust is adopted almost everywhere.
    • C got C35, developers of C35 have finally made something as good as Rust… and nobody cares anymore.

Never "as good as" Rust

Posted Nov 26, 2025 5:11 UTC (Wed) by gmatht (subscriber, #58961) [Link] (2 responses)

C is already BETTER at targeting embedded devices with only 4K of RAM. Gcc is better at compiling legacy code from the previous century, and small snippets of code that directly interfaces with this legacy code.

Given that there are always trade-offs, it seems a safe bet that C35 will still be better at things C is good at and not as good at things Rust is good at. There would be no point in turning C into just another Rust.

Never "as good as" Rust

Posted Nov 26, 2025 7:13 UTC (Wed) by mb (subscriber, #50428) [Link] (1 responses)

>C is already BETTER at targeting embedded devices with only 4K of RAM

Why?
I do use Rust on an AtTiny861a with 512 bytes of RAM.

There are a couple of quirks in the current experimental compiler implementation.
But there's nothing in Rust as the language itself that would make it incapable or even worse than C on tiny platforms.
The last thing that is missing in the language itself is in place initializations, which we will get in the near future. But I can live without them for the time being.

Never "as good as" Rust

Posted Nov 26, 2025 12:13 UTC (Wed) by Wol (subscriber, #4433) [Link]

> >C is already BETTER at targeting embedded devices with only 4K of RAM

> Why?

And Forth is (allegedly) better still.

So that's no argument against Rust. If it was, embedded developers wouldn't be using C.

Cheers,
Wol

Memory-safe C code

Posted Dec 2, 2025 11:02 UTC (Tue) by anton (subscriber, #25547) [Link] (1 responses)

Bounds checking is worth talking about, because Algol 60 (which usually was implemented with bounds checking) and Algol 68 failed to catch on (at least to the same degree as C), while C (which passes arrays as pointers without size information) caught on and a lot of code is written in C. Interestingly, in the Linux man-pages 6.03 I see things in the spirit of Deputy, like
void *memmove(void dest[.n], const void src[.n], size_t n);
which indicates how n relates to the passed pointers. Is this a C23 innovation? In any case, some Deputy-like features are finding the way into C, 15 years later.

There are no invalid pointers in Lisp (released 1960) and many later languages (e.g., Java), so why are you talking about that? Because invalid pointers in C code are a problem, and there is lots of C code around.

Concerning compile-time vs. run-time checking, Ivy/Deputy is like Rust: Checking at run time what cannot be checked at compile time. Maybe Ivy/Deputy cannot do all the things that Rust can do, but that would be just an issue of adding the additional features to the safe C variant.

A bigger problem in that context is probably that in some cases you would either stay with unsafe C in significant pieces of code or have to do thinks like Rust does with Rc or Arc (run-time reference counting and checking), a cost that C programmers that think that their code is correct do not want to take, so they will leave the C code for handling the data structure unsafe. Still, I think that in much code, lots of code could be converted to such a safe C variant with less effort than rewriting it in Rust.

Memory-safe C code

Posted Dec 2, 2025 11:17 UTC (Tue) by alx.manpages (subscriber, #145117) [Link]

> Interestingly, in the Linux man-pages 6.03 I see things in the spirit of Deputy, like
>
> void *memmove(void dest[.n], const void src[.n], size_t n);
>
> which indicates how n relates to the passed pointers. Is this a C23 innovation?

C has no such syntax. It was sugar used in the manual pages for documentation purposes.

I used that syntax for a few versions. It's a syntax that was discussed for some time (including in GCC and the C Committee), but we found out it wasn't great. In C, you can't use stuff before declaring it (we had implicit declarations in K&R C, but we got rid of those for good). It can cause cyclic dependencies, etc.

More recently, I've changed the Linux man-pages to use a syntax that is an old GNU extension:

wchar_t *
wmemcpy(size_t n;
wchar_t dest[restrict n], const wchar_t src[restrict n], size_t n);

This is perfectly valid C code for GCC. It looks a bit redundant, but it's okay, because the compiler verifies everything, and it's difficult to make bugs using it.

In the case of memcpy(3), the latest version of the manual pages has

void *
memcpy(size_t n;
void dest[restrict n], const void src[restrict n], size_t n);

which isn't valid because arrays of void are not valid. However, everything else is valid GNU C. I decided to use this sugar with void, for having more useful documentation.

See also: <https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html>.

Memory-safe C code

Posted Nov 16, 2025 0:45 UTC (Sun) by Cyberax (✭ supporter ✭, #52523) [Link] (1 responses)

Macros in C can only buy you safe array access, but they can't prevent use-after-free. Unless you go into full automatic reference counting for all objects (i.e. performance killer). And you can't do really anything about concurrency.

Memory-safe C code

Posted Nov 16, 2025 6:55 UTC (Sun) by alx.manpages (subscriber, #145117) [Link]

Agree.

I suspect we could probably add some attributes or qualifiers to get Rust-like semantics that prevent use-after-free.

But even if we only get rid of buffer overflows, that would still be an important change.

BTW,

> Macros in C can only buy you safe array access

Even safe array parameter (thus, pointer) access, after some feature I'm working on.

Memory-safe C code

Posted Nov 16, 2025 13:28 UTC (Sun) by tialaramex (subscriber, #21167) [Link] (12 responses)

So, the trouble is that Rust actually goes a little beyond memory safe - though that's the headline feature. All the stuff that's Undefined Behaviour in C or C++ is either well defined in safe Rust or does not exist. This rules out things that aren't typically associated with remote code execution or even segfaults but have Undefined Behaviour because we can't actually say they're safe, even though we might suspect in practice they are.

I *think* if you're restricted to only the unsigned integer types and only a few arithmetic operators (not including division) you can make a "safe C" but I could be wrong, and anyway it's too restricted to be of any practical use.

In particular I'm pretty sure a "safe C" cannot have pointers at all. Safe Rust is allowed to make pointers, because it isn't allowed to dereference them and in Rust all the pointers are allowed to exist, even if they're nonsense, so long as we do not dereference them - in contrast my understanding is that in C nonsense pointers are prohibited because historically they might be impossible at runtime on some hardware.

Memory-safe C code

Posted Nov 16, 2025 15:13 UTC (Sun) by alx.manpages (subscriber, #145117) [Link] (4 responses)

About UB, in C we're now gaining an attribute that makes the behavior well-defined for signed overflow, but keeps diagnostics. Kees talked about it in the Linux Security Summit. I think that's a good approach.

Another thing is that C is removing many of the Undefined Behaviors. In the last year, the C Committee has transformed many UBs into constraint violations (mandatory diagnostic) or well-defined behavior, depending on the case. https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3529.pdf

About safety and pointers, I think it's not only possible, but easy. - Make sure all pointers have a provenance. This disallows things like (int *)42. (int*) 42; // diagnostic - Make sure all pointers are paired with a variable holding the number of elements in the array (with the only exception being functions that *read* null-terminated strings).
void f(int p[]);  // diagnostic
void g(size_t n, int p[n]);  // ok
- Assume that pointers with no specified length only have one element.
void h(int *p)  // p is a pointer to a single integer.  Pointer arithmetic not allowed.
{
    *p = 42;  // ok
    p++;  // diagnostic
}
- Make sure pointers are non-null before dereferencing.
void i(_Optional int *p)
{
    *p;  // diagnostic
    if (p != NULL)
        *p;  // ok
}
- Make sure pointer arithmetic is within the bounds specified by the number of elements.
void j(size_t n, int a[n])
{
    a[countof(a) - 1] = 42;  // ok
    a[countof(a)] = 7;  // diagnostic

    for (int i = 0; i < countof(a); i++)  // ok
        a[i] = 0;
    for (int i = 0; i < countof(a) + 1; i++)  // diagnostic
        a[i] = 0;

    a[42] = 0;  // diagnostic (42 not proved within [0,countof(a)).
}
--- These restrictions can't be used by every program, so some code might need to turn some of these off, but most programs could enforce all of this via a set of -Werror=... flags.

Memory-safe C code

Posted Nov 17, 2025 13:16 UTC (Mon) by plugwash (subscriber, #29694) [Link] (1 responses)

> About safety and pointers, I think it's not only possible, but easy. - Make sure all pointers have a provenance.

Provenance alone is insufficient, that a pointer was valid at some time in the past does not mean it is still valid now.

Memory-safe C code

Posted Nov 17, 2025 13:22 UTC (Mon) by alx.manpages (subscriber, #145117) [Link]

I'm aware of that. I said previously that I intend to resolve buffer-overflows, not use-after-free.

While both are connected, they're different, and the solutions need to be different. It's quite easy to remove buffer overflows in C, but it's more complex to resolve use-after-free bugs.

Memory-safe C code

Posted Dec 13, 2025 23:48 UTC (Sat) by sammythesnake (guest, #17693) [Link] (1 responses)

I'm not a C programmer* but I have aa feeling that you still have problems with the following:

int a[] = []; /* or however you spell this in C */

j(0, a)

because

a[countof{a} - 1]
is out of bounds, right?

* By firm choice - every time I even think about C, I'm bemused that anyone would choose a language apparently composed entirely of foot guns. If I ever need anything closer to the iron then higher level languages, I'll go for rust, but I've never had enough reason to actually learn it properly so far. YMMV, of course!

Memory-safe C code

Posted Dec 14, 2025 0:16 UTC (Sun) by alx.manpages (subscriber, #145117) [Link]

Yup, I got a mistake in the example. It should have been:
void j(size_t n, int a[n])
{
    a[countof(a) - 1] = 42;  // diagnostic
    if (countof(a) >= 1)
        a[countof(a) - 1] = 42;  // ok
    a[countof(a)] = 7;  // diagnostic

    for (int i = 0; i < countof(a); i++)  // ok
        a[i] = 0;
    for (int i = 0; i < countof(a) + 1; i++)  // diagnostic
        a[i] = 0;

    a[42] = 0;  // diagnostic (42 not proved within [0,countof(a)).
}

MISRA C might be provably safe.

Posted Nov 19, 2025 12:57 UTC (Wed) by gmatht (subscriber, #58961) [Link] (6 responses)

Much of the difficulty of proving the safety of C is use-after free and double-frees. MISRA-C solves this by completely banning the use of dynamically allocated memory (even in memory-safe languages; you don't want your brakes to fail when malloc does). In MISRA-C:2012 there is also the advisory rule 17.5 which requires that array parameters to functions should have bounds specified.

For all I know MISRA-C is provably safe. I have seen many claims that MISRA is safe, but the context implies that they mean safe in an informal English sense of the word.

I wouldn't want to write a word processor in MISRA-C, but I understand there is a lot of safety-critical code written in MISRA-C. If there isn't a memory-safe compiler for MISRA-C there should be.

MISRA C is not provably safe.

Posted Nov 19, 2025 14:22 UTC (Wed) by tialaramex (subscriber, #21167) [Link] (5 responses)

MISRA-C is basically a glorified style guide so, no, it's definitely not "provably safe" in a useful sense.

MISRA-C;2012 R17.5 describes an ambition C cannot fulfil. It might almost as well say "Programs shall not have bugs". For rule 17.5 it wants to specify that the array size is part of the parameter type, but in C that is nonsense, the array types always decay to pointers here. You can write this out in C but C compilers will ignore your intent.

You can actually do what MISRA-C calls for here in Rust, and I have, exactly once, because it's very rarely actually useful. The case where I did took memory pages, they're always exactly 4096 bytes long (no, I don't handle huge pages), and I specified that the function takes only (references to) arrays of precisely 4096 bytes, so for Rust passing some other size won't compile for the same reason you can't pass a boolean to a function which takes a string - they're different types. C doesn't provide any such thing and MISRA can't imagine it into existence.

Obeying MISRA's style is a sign of compliance, which is a useful trait for safety systems, but to a considerable extent it's functioning as a Brown M&M check, it's not a proof of anything.

MISRA C is not provably safe.

Posted Nov 20, 2025 12:10 UTC (Thu) by khim (subscriber, #9252) [Link] (2 responses)

> You can write this out in C but C compilers will ignore your intent.

C compiler would, but there are other programs that wouldn't. It's the same story as Ada and SPARK, Rust and mrustc, etc.

The big question is whether full-blown checker for MISRA C exists or may even theoretically exist. PVS-Studio claims 80% coverage.

> they're always exactly 4096 bytes long (no, I don't handle huge pages)

What about 16KiB pages? MacOS uses them and Android moves there, too.

> but to a considerable extent it's functioning as a Brown M&M check, it's not a proof of anything

You can as well only use Rust with mrustc and claim that all these lifetime markups are just a wishful thinking. The big question about MISRA C is how much enforcement can be done automatically with existing tools, not whether C decays pointers. Sure, it decays them but for the MISRA C it's not a problem if you have an external checker.

MISRA C is not provably safe.

Posted Nov 21, 2025 10:10 UTC (Fri) by taladar (subscriber, #68407) [Link] (1 responses)

Are you seriously comparing the situation in C where everyone is using compilers that do not do these checks along with rumored full blown checkers that basically no C programmer ever tried with people on Rust using the standard compiler that everyone uses and a strawman user who uses mrustc, a compiler only used for bootstrapping?

MISRA C is not provably safe.

Posted Nov 21, 2025 11:52 UTC (Fri) by khim (subscriber, #9252) [Link]

We are talking about MISRA C here, isn't it?

All companies that I knew about with MISRA C aspirations have verifiers that they use to ensure [partial] compliance. Yes, these checkers do have bugs and don't catch 100% of violations, but so does Rust.

Thus I have no idea what are you talking about here, sorry: MISRA C and Rust approaches are very comparable.

Why not?

Posted Nov 21, 2025 14:17 UTC (Fri) by gmatht (subscriber, #58961) [Link] (1 responses)

The major innovation in Rust is the borrow checker. This does not accept all valid programs but (should) only accept valid programs.

Writing a general borrow checker for C is hard because C lacks the lifetime annotations and valid standards compliant C code may not conform to the borrow checkers expectations.

However MISRA-C is much more pedantic than the Rust borrow-checker. Since dynamic allocations are banned, unless all lifetimes are static, the program is not valid MISRA-C. And if all lifetimes are static, lifetime annotations are redundant, and lifetime checks are redundant.

There are lots of edge cases to consider, for example, if race conditions could result in memory unsafety. However, it seems that if a compiler is allowed to reject non-MISRA-C this would make it vastly easier to only accept provably safe programs.

Why not?

Posted Nov 21, 2025 15:21 UTC (Fri) by excors (subscriber, #95769) [Link]

> However MISRA-C is much more pedantic than the Rust borrow-checker. Since dynamic allocations are banned, unless all lifetimes are static, the program is not valid MISRA-C. And if all lifetimes are static, lifetime annotations are redundant, and lifetime checks are redundant.

MISRA C still allows automatic storage duration (i.e. stack variables), so not all lifetimes are static, and you can get bugs when a stack pointer escapes the function's scope.

MISRA C has the rule "The address of an object with automatic or thread-local storage shall not be copied to another object that persists after the first object has ceased to exist", but that's an explicitly undecidable rule, so it's basically saying "your program must not be buggy".

Some static checkers apparently detect simple violations of that rule (e.g. assigning the address to a global variable or returning it from the function that allocated it: https://www.mathworks.com/help/bugfinder/ref/misrac2023ru...), but I don't believe it's possible to detect all violations in otherwise-compliant code without rejecting plenty of reasonable and fully-compliant code.

Memory-safe C code

Posted Nov 17, 2025 8:29 UTC (Mon) by hunger (subscriber, #36242) [Link] (15 responses)

Think of "unsafe" to be more about limitations of the rust compiler than about properties of the code marked unsafe. Of course there are memory-safe programs written in all kinds of languages -- whether those languages are memory-safe themselves or not!

Any code the rust compiler can not proof to follow all its internal rules needs to be marked `unsafe`. It does not matter whether that is because the code does something tricky that is too complex for the rust compiler to make sense of -- or whether it is just written in some language the rust compiler can not reason about. So *all* non-rust code is by definition `unsafe` in rust, there is no way around that.

`unsafe` is IMHO a needlessly inflammatory name for a marker that basically says "The rust compiler does not fully understand this code", especially when you are communication with other language communities. I guess we are stuck with that name now though :-/

Memory-safe C code

Posted Nov 17, 2025 9:51 UTC (Mon) by taladar (subscriber, #68407) [Link]

But it is not just "code the Rust compiler does not fully understand", it is code where the programmer has to uphold those same safety invariants. Even unsafe code is not allowed to do anything you want that the constructs you can use in unsafe make it possible to do.

Memory-safe C code

Posted Nov 17, 2025 11:38 UTC (Mon) by khim (subscriber, #9252) [Link]

> `unsafe` is IMHO a needlessly inflammatory name for a marker that basically says "The rust compiler does not fully understand this code"

It's absolutely correct and proper marker. Technically the name is TCB (trusted code base), but when I worked in a project with “correct” naming… everyone who arrived on the project invariably wanted to commit something in the trusted folder…

> especially when you are communication with other language communities

Which communities are we talking about? C# with the exact same unsafe keyword or Haskell with System.IO.Unsafe?

IMNSHO name unsafe conveys precisely the right balance between inherent danger and usability.

Rust "unsafe" is not code the compiler doesn't understand

Posted Nov 17, 2025 12:21 UTC (Mon) by farnz (subscriber, #17727) [Link] (12 responses)

Thinking about it as "code the compiler doesn't understand" leads you down the wrong path; it's not that the compiler doesn't understand the code (it does, certainly well enough to generate machine code from it), it's that the compiler cannot prove that the code complies with all language invariants (not least because some of those invariants might be affected by code written in another language), and thus that the programmer is on the hook for ensuring that the language rules are obeyed. It may, of course, be impossible for the programmer to ensure that the rules are obeyed, in which case you have a buggy program.

One of the core reasons this is a problem is that we know that non-trivial properties of programs[1] are undecidable in general. This implies that we can only ever sort programs into three categories about a non-trivial line: "property holds", "property does not hold", "property might or might not hold".

This can be made useful by having as few interesting programs as possible fall into the "property might or might not hold" category, and then approximating the true answer by asserting that the "property might or might not hold" category is equivalent to "property holds" or "property does not hold" for all programs we care about. There's just one issue with this: sometimes, the approximation we choose is "wrong" from a human perspective, and we either reject a program that "should obviously" work, or we "miscompile" a program that "should obviously" always generate a compile error.

In turn, that leads to a dilemma; if you go down the route of miscompiling programs that should obviously always generate a compile error, programmers who didn't intend their program to have a bug will accidentally write buggy code that isn't caught by review, while if you choose to reject programs that should obviously work, programmers will get frustrated that they can't find a way to express something that clearly make sense.

unsafe gives Rust a way out of the dilemma; without unsafe, Rust promises that the approximation of any property it checks will result in Rust rejecting the program erroneously, at worst, while with unsafe, the compiler may "miscompile" programs. It's then on the programmer to decide which behaviour they want - do you want the more expressive "Unsafe Rust" dialect, with the increased risk of bugs, or do you want the lower bug risk of the "Safe Rust" dialect, but with the inability to express some things that are perfectly reasonable?

[1] As an example of a non-trivial property, "does this program read from free memory, or only allocated memory" is non-trivial.

Rust "unsafe" is not code the compiler doesn't understand

Posted Nov 17, 2025 16:04 UTC (Mon) by khim (subscriber, #9252) [Link] (11 responses)

> [1] As an example of a non-trivial property, "does this program read from free memory, or only allocated memory" is non-trivial.

That's important “non-trivial property”, sure, but it's not the most devastating one. The critical “non-trivial property”, that also can not be tested is “does that programs always behave identically to naïvely generated code with zero optimizations or not” is also undecidable.

This, essentially, blows up the whole “undefined behavior is reading error” idea to spliters: we may argue about whether undefined behavior is reading error or not till we are blue in face, but the simple fact remains: it's mathematically impossible to write a C compiler that wouldn't “miscompile” some programs with undefined behaviors… the only question is which programs it may miscompile and which ones it should compile correctly… but that's question of changing the undefined behaviors list, not question of changes to the underfined behavior definition.

Rust "unsafe" is not code the compiler doesn't understand

Posted Dec 14, 2025 11:56 UTC (Sun) by sammythesnake (guest, #17693) [Link] (10 responses)

The problem isn't so much that a compiler will "miscompile" a program with UB - by definition, "undefined behaviour" means there is no definition of what the compiler ought to produce to point at, so any behaviour is "correct" and "miscompilation" is A Priori impossible.

The *actual* problem is the way the border around the territory of nasal demons is defined.

It is possible to define languages where it is impossible to write a program with UB. C is not that language.

It is possible to design a programming language where the realm of UB is clearly delimited by simple rules that can easily be checked by a human of mortal intellect. C is not that language.

It is possible to design a programming language where the realm of UB is technically delimited by rules that can be checked before the heat death of the universe by a computer that could, in principle, be constructed. C is not that language.

It is possible, though of questionable utility/wisdom, to design language where the realm of UB is defined in terms of mathematically undecideble, fundamentally unsolvable problems (such as the Halting Problem}. THIS is the language C is.

Writing a non-trivial C program without UB *may* be possible, using MISRA style, intrinsics, compiler extensions etc. but doing so in standard C *and proving there is no UB* is not.

That's not my idea of an effective way to communicate with the computer...

IFF you can exclude UB, then there are large classes of provably equivalent constructions that can reliably underlie optimisations. With UB, *all* transformations are "correct", including "return 0;" -> "emit_olfactory_fiends();"

Rust "unsafe" is not code the compiler doesn't understand

Posted Dec 14, 2025 12:10 UTC (Sun) by alx.manpages (subscriber, #145117) [Link] (3 responses)

> Writing a non-trivial C program without UB *may* be possible, using MISRA style, intrinsics, compiler extensions etc. but doing so in standard C *and proving there is no UB* is not.

Indeed, standard C is a terrible dialect of C. We're working on improving that, but I strongly recommend using extensions that provide safety that the standard can't provide.

Please don't judge C by one of its worst dialects. Those judgements feel disconnected from reality, when one can write C programs that are safe from many (admittedly, not *yet* all) of the concerns that are often associated with C.

Rust "unsafe" is not code the compiler doesn't understand

Posted Dec 14, 2025 13:24 UTC (Sun) by mb (subscriber, #50428) [Link] (2 responses)

>standard C is a terrible dialect of C [...]
>Please don't judge C by one of its worst dialects. Those judgements feel disconnected from reality

Judging C by its ISO standard is disconnected from reality?
Really?

Can I tell the trolls that they are disconnected from reality when they demand a Rust standard next time?

Rust "unsafe" is not code the compiler doesn't understand

Posted Dec 14, 2025 14:04 UTC (Sun) by alx.manpages (subscriber, #145117) [Link] (1 responses)

> Judging C by its ISO standard is disconnected from reality?
> Really?

Yes. Just like make(1) is a great language (especially, GNU make(1)), and POSIX --and ISO standard-- make(1) is unusable (actually, POSIX.1-2024 seems to have improved make(1) significantly, and some people claim it is now in a usable state; I haven't checked myself, so I can't comment).

As someone said, the standard is toilet paper. Except when it's useful, of course.

> Can I tell the trolls that they are disconnected from reality when they demand a Rust standard next time?

I don't care. I'll only say that I have never demanded a Rust standard.

Rust "unsafe" is not code the compiler doesn't understand

Posted Dec 14, 2025 14:05 UTC (Sun) by alx.manpages (subscriber, #145117) [Link]

> and POSIX --and ISO standard-- make(1)

I meant to write '--an ISO standard--'.

Rust "unsafe" is not code the compiler doesn't understand

Posted Dec 14, 2025 12:25 UTC (Sun) by malmedal (subscriber, #56172) [Link] (5 responses)

> With UB, *all* transformations are "correct", including "return 0;" -> "emit_olfactory_fiends();"

Yes. However this is not a law of nature. Or inherent in the language itself. The committee *could* have made the opposite decision is they had wanted...

Rust "unsafe" is not code the compiler doesn't understand

Posted Dec 14, 2025 13:17 UTC (Sun) by alx.manpages (subscriber, #145117) [Link] (4 responses)

And indeed the committee is currently revising a lot of UBs in the standard and changing it to mandatory diagnostics, which is objectively better (and in other cases, turning undefined into defined, but we're more careful about that, as it might have negative consequences).

Rust "unsafe" is not code the compiler doesn't understand

Posted Dec 14, 2025 14:39 UTC (Sun) by malmedal (subscriber, #56172) [Link] (3 responses)

Sounds promising. Any details available yet, or are these internal discussions?

Rust "unsafe" is not code the compiler doesn't understand

Posted Dec 14, 2025 14:48 UTC (Sun) by alx.manpages (subscriber, #145117) [Link] (2 responses)

> Sounds promising. Any details available yet, or are these internal discussions?

There are results already. The current draft for C2y has lost a lot of UB.

Here's a summary from earlier this year of what has been done already, what is in progress, and what may come in the future:
<https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3529.pdf>.

The current draft for C2y is here, in case you want to have a look at it:
<https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3685.pdf>.

Rust "unsafe" is not code the compiler doesn't understand

Posted Dec 14, 2025 15:12 UTC (Sun) by malmedal (subscriber, #56172) [Link] (1 responses)

Thank you, looks very much like an improvement, though I am confused by terms such as ghost and earthly demons :)

Rust "unsafe" is not code the compiler doesn't understand

Posted Dec 14, 2025 15:25 UTC (Sun) by alx.manpages (subscriber, #145117) [Link]

> Thank you, looks very much like an improvement,

Thanks! :)

> though I am confused by terms such as ghost and earthly demons :)

Writing standards proposals can be boring. Using these terms can make it more entertaining. These come from "nasal demons".

We started using "earthly demon" to refer to those cases of UB that can be perfectly determined at compile time, and thus can be transformed into constraints (mandatory diagnostics).

We later added the term "ghost" those cases that the standard specifies as UB, but which are impossible to trigger (because some other clause of the standard precludes the possibility entirely). These are just removed from the standard, as they are just incorrect text.


Copyright © 2025, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds