Rod said:
I read a security oriented pdf (sorry, don't know where anymore) which said:
1) 15 C functions suffer buffer overflow problems:
gets() cuserid() scanf() fscanf() sscanf() vscanf() vsscanf() vfscanf()
sprintf() strcat() strcpy() streadd() strecpy() vsprintf() strtrns()
2) 8 C functions suffer from format string vulnerabilities
printf() fprintf() sprintf() snprintf() vprintf() vfprintf() vsprintf()
vsnprintf()
Summary of pdf: Because many C implementations use the same stack for
string data and flow control information (like addresses), the above
functions can modify the flow control information on the stack thereby
allowing authorized code to execute.
That's only one kind of catastrophic failure. Personally, I would be
more focused on the fact that the failures happen in the first place.
If you really want to get crazy with C, do some of these:
1) eliminate pointers in main
Huh? I probably need some elaboration here. Do you literally mean that
you shouldn't have local variables in main that are passed by reference
to other functions? Or ... what *do* you mean?
2) make pointers be associated with a variable before use, not with a data
type
Huh? You mean that building linked lists and similar data structures
should take an additional operation (first assign the new node malloc to
a variable) or do you mean that making such things should be impossible?
3) eliminate malloc, add dynamic allocation and garbage collection
Ok, but then you are no longer programming in C. C is a language that
allows you to understand the *performance* of your application very
clearly. Java is a language allows you to understand what it *does*
very clearly. The two languages are differentiated by this difference
in philosophy. Making C more like Java is just as easily achieved by
throwing it out and starting with Java.
However, I understand the motivation. Why not instead ask for *more*
from the C universe? There are many ways of *extending* the whole
malloc/etc paradigm to make it safer, *faster* and more powerful.
4) change C to pass by reference
Ok, no. Adding refs (the & thingy from C++) I agree with, because
passing pointers tends to more dangerous in general (more likely to pass
in NULL, or garbage/uninitialized pointers) for some cases. However to
be general, you must support *both* semantics, and C does this by
allowing you to pass a pointer in lieu of references. But don't take
away call by value from the language.
5) require separation of string (and other) data and flow control
information
You mean don't throw growable data types into non-growable arrays on a
stack? I agree. Bstrlib makes exactly this distinction (there is no
sane way to put a non-constant bstring on the stack). Perhaps only
allowing bounds protected enforced types into auto variables.
6) give up now, and try Walter Bright's D language...
Because "C++++" would have been too tacky. You could instead look at
languages like Python, Lua, and Java and ask yourself, what would it
take to design a language that was as easy to use as Python/Lua, and
safe and predictable as Java, with the speed of C?