I wonder whether the most expensive mistake is not so much the NUL-terminated string design, but the persistent use of library string and memory manipulation functions that we now call "unsafe". The culture of constantly writing your own raw-memory-based string manipulation functions and working with memory so directly, without safety constraints.
I remember using strings and STL containers in C++ and wondering why would anybody go back to the clunky ways of malloc'ing, scanning for NULs, using memcpy, strcmp and other things that might "run away" on you so easily. I remember feeling unsafe using strcpy. In contrast, it felt very safe to use C++ strings: I had to out of my way to code a buffer overflow.
Better, but not best, the "safe" replacements of strncpy require you to maintain the correct string length on your own. Basically, there are just so many ways to shoot yourself in the foot.
The industry could've signficantly addressed this by adapting a standard library for manipulating strings and memory, at least with length-restricted "safe" functions (strncpy, but one that always NUL-terminates). Potential language support and compiler support could've been added. All of this should've been done way back in the day, but it wasn't.
That subjective feeling of unsafety is excellent. I can only wish that other people felt that same tinge of doubt when invoking these operations, as one mistake can corrupt memory.
I also find it ridiculous how tolerant the OSS community is about these things. Major projects written in C (Pidgin) often find themselves fixing these sorts of mistakes over and over again. Why is this acceptable? To me it suggests a rushed design, and it potentially puts my information at risk. Remember, all of the speed gains to be had from C are lost the moment you core dump.
It isn't that C is inherently insecure, but we should require good reasons for it to be used, particularly with apps that interact with the network. Right now it seems like it has a bit too much geek cred as the language of alpha developers.
It is trivial to write a function like strncpy_term() that adds a terminating NUL and drop it into any C project you write.
Potential language support and compiler support could've been added. All of this should've been done way back in the day, but it wasn't.
I would argue that since C became the de facto high-level lingua franca of low-level programming, it was better to keep it minimalistic so that programs written in C would be as portable as possible.
I remember using strings and STL containers in C++ and wondering why would anybody go back to the clunky ways of malloc'ing, scanning for NULs, using memcpy, strcmp and other things that might "run away" on you so easily. I remember feeling unsafe using strcpy. In contrast, it felt very safe to use C++ strings: I had to out of my way to code a buffer overflow.
Better, but not best, the "safe" replacements of strncpy require you to maintain the correct string length on your own. Basically, there are just so many ways to shoot yourself in the foot.
The industry could've signficantly addressed this by adapting a standard library for manipulating strings and memory, at least with length-restricted "safe" functions (strncpy, but one that always NUL-terminates). Potential language support and compiler support could've been added. All of this should've been done way back in the day, but it wasn't.