Expert · Bits, undefined behaviour and safety · topic 44 of 60 · 25 min
Secure and defensive C
Explanation
Why C needs extra care
C gives no automatic bounds checks, no automatic memory management and no exceptions. A missed check rarely produces an error message; it produces corrupted memory, a crash much later, or an exploitable security hole. A large share of serious security vulnerabilities in operating systems and browsers over the years have been memory-safety bugs in C and C++ code. Defensive habits are therefore part of writing C professionally.
Check every return value
FILE *f = fopen(path, "r");
if (!f) { perror(path); return -1; }
char *buf = malloc(n);
if (!buf) { fclose(f); return -1; } /* clean up what you already have */
if (fscanf(f, "%d", &count) != 1) { … }
if (fclose(f) != 0) { perror("fclose"); }Validate input at the boundary
Data from users, files, networks and sensors can be any length and any value. Check it where it enters the program: lengths before copying, ranges before using as indexes or sizes, formats before parsing. Inside the program, functions can then rely on valid data (and use assert to document that assumption, module 11).
Integer overflow in size calculations
/* Attacker sends count = 1073741825 records of 4 bytes each.
count * 4 overflows a 32-bit size, so malloc gets a tiny number,
and the loop then writes far past the small buffer. */
uint32_t count = read_count();
if (count > SIZE_MAX / sizeof(uint32_t)) return -1; /* would overflow: reject */
uint32_t *items = malloc((size_t) count * sizeof *items); /* or use calloc(count, sizeof *items) */Hardening flags
gcc -std=c17 -O2 -Wall -Wextra -Wformat=2 -Wconversion \
-D_FORTIFY_SOURCE=2 -fstack-protector-strong -fPIE -pie \
prog.c -o progCoding standards used in industry
- SEI CERT C Coding Standard (Carnegie Mellon University): rules and recommendations for secure C, such as "do not form or use out-of-bounds pointers" and "guarantee that storage for strings has room for the null terminator".
- MISRA C: guidelines for safety-critical embedded software, widely required in automotive (and used in aerospace, rail and medical devices). It restricts risky features: for example dynamic memory allocation after start-up, unrestricted goto, and implicit conversions.
- Static analysis tools check code against these rules automatically: gcc -fanalyzer, clang-tidy, cppcheck, and commercial tools used by automotive suppliers.
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Secure and defensive C · 1/6
In this lesson you will learn the habits of secure, defensive C.
Prefer a video by a teacher? Find free videos on “secure c programming cert c misra c defensive coding” on YouTube ↗
In real life: Reading a length-prefixed message safely
A server for IoT devices receives messages with a 2-byte length followed by data. Code that trusted the length would read beyond the received bytes. The safe version checks the claimed length against the bytes actually received and against its own maximum before copying.
#define MAX_MSG 512
int handle_message(const uint8_t *data, size_t received, uint8_t out[MAX_MSG], size_t *out_len) {
if (received < 2) return -1;
size_t claimed = (size_t) data[0] << 8 | data[1];
if (claimed > received - 2 || claimed > MAX_MSG) return -1; /* never trust the length field */
memcpy(out, data + 2, claimed);
*out_len = claimed;
return 0;
}Practice (0/3 done)
Why check count > SIZE_MAX / size before malloc(count * size)?
Which coding standard is widely used for safety-critical automotive C?
Take a small C program you wrote earlier in this course and review it like a security auditor: list every place that reads external input, every return value that is ignored, every fixed-size buffer and every multiplication used for a size. Fix each finding, add hardening flags to your build, and run it with sanitizers.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Function pointers and callbacksBits, undefined behaviour and safety · same module
- Masks and flagsBits, undefined behaviour and safety · same module
- Secure coding basicsCyber Security: from zero to SOC analyst · Malware and web security
- Classic C++ pitfalls in contests and coding roundsC++ Programming (modern C++ and DSA) · Competitive programming, interviews and careers
- Memory leaks and other heap bugsDynamic memory
- Understanding constraints and fixing overflowFlutter and Dart · Layouts
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
What caused the Heartbleed bug?
Answer: Trusting a length field and copying more bytes than were received
Unchecked length → memory leak to the attacker.
What is the first habit for robust C?
Answer: Checking every return value
Failures must be noticed.
What does -fstack-protector-strong add?
Answer: A canary that detects stack buffer overflows before returning
Aborts on "stack smashing".
Which tool can statically analyse C code for bugs?
Answer: clang-tidy or cppcheck
Also gcc -fanalyzer.
Where must input validation always happen?Related
What does scanf return?Related
Answer: The number of items successfully read (or EOF)
Check it against the expected count.
What does malloc return when it cannot allocate?Related
Which flag combination helps catch out-of-bounds and undefined behaviour while practising with GCC?Related
Answer: -fsanitize=address,undefined -D_GLIBCXX_DEBUG
Sanitizers and the debug STL report errors at the faulty line.
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 1 more topic in “Bits, undefined behaviour and safety” before its exam: Function pointers and callbacks.
- Module 9 exam: Bits, undefined behaviour and safety · 12 questions · 25 min, without help. 5 topics of this module still to finish first.
- Then the next module, Data structures in C. 60 topics left in the course before the final exam.