The C Bible: Old Testament and New Testament
Introduction
It has been in my mind for some time on the type of reference books if one want to learn the C programming language, most recommends "The C Programming Language" also known as C Bible written by Dennis Ritchie and Brian Kernighan.
It is a great book on C fundamental, however the book is implementing ANSI-C or synonymous with C89 --> a C standard made in 1989. This raises concerns about the relevance of classic C programming books in today's world.
The Problem with Classic C Programming Books
Classic C programming books, written in the 1970s and 1980s, introduced the C language and provided a foundation for generations of programmers. However, these books were written in a different era, when security and safety were not as prominent concerns. One major issue with these books is their reliance on outdated functions that can lead to buffer overflows, null pointer dereferences, and other security vulnerabilities.
Insecure Functions: strcpy, strcat, and strcmp
Functions like strcpy, strcat, and strcmp are commonly used in classic C programming books, but they are inherently insecure. For example:
- strcpy: Copies a string without bounds checking, making it easy to overflow a buffer and potentially execute malicious code.
- strcat: Concatenates two strings without checking the bounds of the destination buffer, leading to buffer overflows and other security issues.
- strcmp: Can access memory outside the bounds of the strings if they are not null-terminated, leading to undefined behavior.
The Safer Alternatives: strncpy, strncat, and strncmp
Fortunately, there are safer alternatives to these functions:
- strncpy: Copies a string with a maximum length parameter to prevent buffer overflows.
- strncat: Concatenates two strings while checking the bounds of the destination buffer.
- strncmp: Compares two strings with a maximum length parameter to prevent accessing memory outside the bounds of the strings.
Why Modern C Safety Features Matter
Modern C safety features are crucial in today's world, where security is a top concern for software development projects. With the rise of connected devices, IoT, and cloud computing, the potential attack surface has increased exponentially. Using outdated functions like strcpy and strcat leaves us open to security vulnerabilities and other risks. By incorporating modern safety features, we can write more robust, reliable, and secure code.
The Importance of Compiler Flags and ASAN
Another cons of outdated C references: the old books did not even mentioned the use of compiler flags and address sanitizers! These modern tools can prove to be instrumental to write a safe C program.
Compiler flags like -Werror and -Wall can help catch common errors and warnings, such as unused variables, uninitialized variables, and type mismatches.
Address Sanitizers (ASAN) are another powerful tool that can detect memory corruption, buffer overflows, and other security issues. By enabling ASAN, you can catch errors like use-after-free, double-free, and invalid memory accesses.
To use these tools effectively, you can add the following flags to your compiler command: -Werror -Wall -fsanitize=address
. This will help you catch security vulnerabilities and write more secure code.
Conclusion
While classic C programming books are still valuable resources, they can be hazardous if not used carefully. By relying on outdated functions, we're leaving ourselves open to security vulnerabilities and other risks. It's time to update our C programming practices and start using safer functions like strncpy, strncat, and strncmp. With the right resources and knowledge, we can write modern C code that is both efficient and secure.
Note: As a programmer who writes in C, Zig, and Rust, I followed a series of memory safety tests to see which language would be most prone to memory errors. The results were telling:
- Rust: As expected, Rust passed with flying colors. With its strong focus on memory safety, it's no surprise that Rust didn't produce any memory errors.
- Zig: Similarly, Zig also performed flawlessly, with none of the tests causing memory errors.
- Modern C: However, the results for C were more surprising. By using specific compiler flags, I was able to harden C to the point where it was on par with Zig. In other words, C also produced zero memory errors.