Comment by ralphc

17 hours ago

How does "Modern" C compare safety-wise to Rust or Zig?

Modern C still promptly decays an array to a pointer, so no array bounds checking is possible.

D does not decay arrays, so D has array bounds checking.

Note that array overflow bugs are consistently the #1 problem with shipped C code, by a wide margin.

  • The thing is though that even with array bounds checking built into the language, out of bounds access due to programming error can still be attempted. Only this time it's safer because an attacker can't use the bug (which still exists) to access memory outside of bounds. In any case, the program still doesn't work as intended (has bugs) because the programmer has attempted, or allowed the attempt, to access out of bounds memory.

    Writing safe code is better than depending on safety features. Writing safe code is possible in any programming language, the only things required are good design principles and discipline (i.e. solid engineering).

  • > no array bounds checking is possible.

    This isn’t strictly true, a C implementation is allowed to associate memory-range (or more generally, pointer provenance) metadata with a pointer.

    The DeathStation 9000 features a conforming C implementation which is known to catch all array bounds violations. ;)

You'd be surprised: Zig has one UB (Undefined Behaviour) that C doesn't have!

In release fast mode, unsigned overflow/underflow is undefined in Zig whereas in C it wraps.

:-)

Of course C has many UBs that Zig doesn't have, so C is far less safe than Zig, especially since you can use ReleaseSafe in Zig..

Modern C is barely any different than older C. The language committee for C is extremely conservative, changes tend to happen only around the edges.

There's finally a way to safely add two signed numbers, without tricky overflow checks that may trigger UB themselves!