I recently read about the $subject.
Q: Why does a programming language has built-in trivial insecurity? Or.. it was just in the old times? How could this be?
C was designed at a time when available CPU power was a scarce resource, and there was much less programming done, also. Modern times have changed the context:
This is why almost all newer programming languages include inherent "protections" against buffer overflows, but also cross-typing attacks (when some bytes are made to be interpreted with a different type, e.g. making some code consider an integer as if it was a pointer) and memory allocation woes ("use-after-free"). For buffer overflows, the protection is twofold:
Unfortunately, such protections cannot be generically backported to C. For instance, the C specification allows for writing out a pointer value into a file, and then, later on, reading it back -- and the pointer MUST still be valid. It is mathematically infeasible to write a garbage collector which can handle this case. There is a GC for C and C++, but (by nature) it cannot really support every "legal" C program.
In other words, if you "modify" C so that it is more robust against buffer overflows, then it no longer is "C", but something else (which you could call "Java" or "C#"). The original C is still used widely, sometimes for a good technical reason (e.g. to write code on a very small platform, like a smart card), but mostly out of tradition and for easier integration with all the existing libraries.
C is an simple language that's quite easy to translate back into Assembly / Machine Language (compared to modern languages) when you neglect optimizations.
C is not so much flawed with insecurities, its just C doesn't force you to always do things in a safer way like some other modern languages. A program running on a Bell Labs PDP-10 in the 1970s by skilled engineers had different requirements than a modern web server connected to the internet that may be attacked by skilled adversaries. Back then, you wanted the language to be fast and dead simple and so many simple sanity checks were left to the programmer.
One of the main 'insecure' parts of C is lack of bounds checking. If you want to copy a string of characters into a new array, the
(Additionally, modern operating systems provide help through features like no-execute, no-write bits and address space layout randomization.)
Granted, its still possible for programmers to make mistakes.
When C was designed in the early 70s, it were different times.
Due to these circumstances, high performance was a much higher concern than security. That's why C omits many sanity-checks on operations and expects that the programmers implement them themself when they feel the need for them and they can spare the resources it costs.
But nowadays, the situation has changed
But on the other hand, hardware resources have become a lot more abundant. The greatest supercomputers from the 70s had a processing power which was several magnitudes below that of todays mobile phones.
For these reasons, the focus of programming languages has shifted from efficiency to security.