Except that safer systems programming languages are older than C with bounds checking by default, having compilers that allowed to disable them if really really required[1]:
Algol (1960)
PL/I (1964)
Modula-2 (1978)
Mesa (1979)
Even VAX, B6500 and 68000 assembly have support for doing bounds checking.
[1] Not the first version of Algol though, as according to Hoare Turing Award speech, customers didn't want unsafe features:
<quote> A consequence of this principle is that every occurrence of every subscript of every subscripted variable was on every occasion checked at run time against both the upper and the lower declared bounds of the array. Many years later we asked our customers whether they wished us to provide an option to switch off these checks in the interest of efficiency on production runs. Unanimously, they urged us not to—they already knew how frequently subscript errors occur on production runs where failure to detect them could be disastrous. I note with fear and horror that even in 1980, language designers and users have not learned this lesson. In any respectable branch of engineering, failure to observe such elementary precautions would have long been against the law. </quote>
That said, we're of course working on changing that with Rust. But I should note that memory safety without garbage collection is just hard: it requires the entire language design to be balanced on a delicate precipice. It's not surprising that it's taken a long time to get there.
I was thinking about this recently and I think a large part of the problem is that C arrays are too weakly typed. Array should be a different type than pointer and they shouldn't be convertible. In particular, you shouldn't be able to subscript a pointer, and the in-memory representation of an array should begin with its length. At that point the compiler can include a runtime bounds check for every array access that it can't prove is safe at compile time.
The reason people use c, is to get higher speed by avoiding those kinds of checks. A real solution most avoid slowdowns.
Turbo Pascal => {$R-}
Ada => pragma Suppress (Index_Check);
Modula-3 => cm3 -A
D => dmd -fnoboundscheck / array.ptr[index] in @system code
Just a few examples. Additionally there are lots of research how to remove bounds checking in compiler optimizations
http://citeseer.uark.edu:8080/citeseerx/showciting;jsessioni...
What C has going for it is the symbiotic relationship with UNIX, 40 years of optimizations in most compilers and the historical baggage of being around for so long.
Other better languages suffered from having been shown the door as UNIX spread into the enterprise, but there was a time when C compilers didn't generate better code as the other ones.
I submitted a link to TLS Lite a few days ago, but, alas, showed poor judgement in timing:
https://news.ycombinator.com/item?id=7564740
Direct link: http://trevp.net/tlslite/
I'm actually rather anxious to hear the knowledgeable crowd discuss this fine project.
What, however, hinders adoption as a "working man's" TLS library? Neglecting performance and variety of cipher support, would or should anything prevent me from using Tiny TLS to secure channels between "inner circle machines" (that talk to a set of well-known participants)?
If you're trying to deploy pure-Python applications, I like tlslite. Of course, I have to say that, because Trevor is much smarter than me.
Personally, I think your realistic production choices are OpenSSL or NSS.
IMO, C fails at being sufficiently low level to do this as well as it could. I don't think C will ever be replaced by a higher level language; it will be replaced with a lower level language that is better at incorporating static analysis of particular usage patterns into the language. To put it another way: C makes you do a bunch of "extra" work compared to other languages without really helping you do that work; other popular languages I know of try to not make you do that "extra" work, which is often a good thing but not always. A true replacement for C will need to still make you do all the "extra" work but help you make sure that work is correct.
E.g.memory allocation: it is not that manual memory allocation and deallocation is necessarily unreliable, but that there is no single way to make it reliable that works well for all programs. But there is also no way to do automatic memory managment that works well for all programs.
I would never recommend C++, but my sense is that current popularity of C++ might be connected to templates which are flexible and powerful in a different way than C or any other language I know of.
(also C was designed for "minicomputers" not mainframes, so not really all that different from its modern usage)
I googled that phrase, and came up empty handed. Could you give an example?
Edit: also worth mentioning that some of the early implementations of this were very inefficient so you might see complaints from that time, but this is not an issue with modern compilers.
That said, are there other ways to fix this class of problem? We have choices. We can continue to build ever-more-advanced tools for patching over the problems of C and C++, or we can start using languages that simply do not have those problems.
There will always be a need for C and C++ in device drivers, microcontrollers, etc. But there's no compelling reason why SSL implementations in 2014 should use languages designed to run on mainframes in 1973.