back

by uecker·1y ago·view on hn ↗
Many real world C programs have no UB.

What Rust attempts to achieve is the possibility of accidentally introducing UB by designing the language in away that makes it impossible to have UB when sticking to the safe subset.

It also possibly to make sure to ensure that C programs have no UB and this does not require any breaking features to C. It usually requires some refactoring the program.

2 comments
> Many real world C programs have no UB.

A bold claim, I've written a whole lot of software in C, and most of it I'd be astonished if it truly has no UB. Even some of the relatively small, carefully written programs probably have edge case UB I never worried about when writing them.

It is certainly true that many C programs have edge cases which trigger UB. I also have written many such programs where I did not care. This does not contradict my statement though. There are programmers who meticulously care (and/or have to care) about getting the edge cases right and this is entirely possible.
I think I worded it poorly. In a real world program, a lot of optimizations rely on assumptions of not triggering UB.

Rephrased:

In a real world program removing all opportunities for UB is in some cases impossible without adding new breaking features to the C language.

This has nothing to do with whether you can or can't write a program without invoking UB. I am talking about a hypothetical large program which does not exhibit undefined behaviour but where if you modified it then you could trigger UB in many ways. The idea I am positing is that to make it such that you could not modify such a program in any way which could trigger UB, would be impossible without adding new breaking features to the C language (e.g. you would need to figure out some way of preventing pointers from being used outside of the lifetime of the object they point to).

This is exactly what I am working on.

But this does not need breaking features, it only needs 1) a opt-in safe mode, and 2) annotations to express additional invariant such as for lifetime. This would not break anything.

It doesn't break existing code, unless you want to statically guarantee that it does not trigger UB, in which case it does. The point is that if you need an opt-in safe mode or annotations to express additional invariants then you can't magically make existing code safe.
A lot of existing code is already safe. You can't prove all (or even most) existing code safe automatically. This is also true for Rust if you do not narrowly define safe as memory safe. You could transform a lot of C code to be memory safe by adding annotations and do some light refactoring and maybe pushing some residual pieces to "unsafe" blocks. This would be very similar to Rust.
> A lot of existing code is already safe.

Again, I am not trying to argue either way. The point I was making was about how you can't define away all UB in the C standard without needing to modify the language in a breaking way.

> You can't prove all (or even most) existing code safe automatically.

No but rust provides a proper type system which goes a long way to being able to prove and enforce a lot more about program behavior at compile time.

> You could transform a lot of C code to be memory safe by adding annotations and do some light refactoring and maybe pushing some residual pieces to "unsafe" blocks. This would be very similar to Rust.

It would only be somewhat similar to super basic entry level rust which ignores all the opportunities for type checking.

> > A lot of existing code is already safe.

> Again, I am not trying to argue either way. The point I was making was about how you can't define away all UB in the C standard without needing to modify the language in a breaking way.

This depends on how you define "breaking". I think one can add annotations and transform a lot of C code to memory safe C with slight refactoring without introducing changes into the language that would break any existing code. You can not simply switch on a flag make existing code safe ... except you can do this too ... it just then comes with a high run-time cost for checking.

> > > No but rust provides a proper type system which goes a long way to being able to prove and enforce a lot more about program behavior at compile time.

> > You could transform a lot of C code to be memory safe by adding annotations and do some light refactoring and maybe pushing some residual pieces to "unsafe" blocks. This would be very similar to Rust.

> It would only be somewhat similar to super basic entry level rust which ignores all the opportunities for type checking.

I do not believe you can solve a lot more issues with strong typing than you can already solve in C simply by building good abstractions.

> You can not simply switch on a flag make existing code safe ... except you can do this too ... it just then comes with a high run-time cost for checking.

I don't think you can reasonably implement this even at a high runtime cost without breaking programs. Either way, you've managed to re-state the crux of my argument.

> I do not believe you can solve a lot more issues with strong typing than you can already solve in C simply by building good abstractions.

Then I don't think you have much familiarity with strong typing or are underestimating the performance impact of equivalently "safe" (in a broader sense than what rust uses the term for) abstractions in C.

The only way to get equivalent performance while maintaining the same level of guarantees in C is to generate C code, at which point you're definitely better off using another programming language.