Beginner · Strings in C · topic 20 of 60 · 30 min
Buffer overflows and safe string handling
Explanation
What happens in memory
void greet(const char *input) {
char name[8];
strcpy(name, input); /* no size check */
printf("Hi %s\n", name);
}
/* greet("Ravishankar Iyer") writes 17 bytes into an 8-byte array */
stack (simplified, addresses grow downward):
| other local data |
| name[8] | ← the copy starts here…
| saved frame pointer | ← …and continues over these
| return address | ← overwriting this can redirect the programIf an attacker controls the input, overwriting the return address can make the program jump to code of the attacker's choosing. This "stack smashing" technique has been behind many famous incidents, from the 1988 Morris worm to bugs found in routers and media players today. Heap overflows (module 6) are just as dangerous.
Unsafe and safer functions
| Avoid | Use instead | Why |
|---|---|---|
| gets(buf) | fgets(buf, sizeof buf, stdin) | gets has no size limit (removed in C11) |
| strcpy(dst, src) | snprintf(dst, size, "%s", src), or check strlen first | strcpy never checks |
| strcat(dst, src) | snprintf, or strncat with the REMAINING space | strcat never checks |
| sprintf(buf, …) | snprintf(buf, sizeof buf, …) | sprintf has no size |
| scanf("%s", buf) | scanf("%19s", buf) or fgets | unbounded %s |
Habits that prevent overflows
- Pass the buffer size along with every buffer: void copy_name(char *dst, size_t dst_size, const char *src).
- Check lengths before copying: if (strlen(src) >= dst_size) reject or truncate deliberately.
- Use sizeof buf at the point where buf is declared as an array; inside functions you only have the size you were passed.
- Validate input lengths at the boundary (where data enters the program).
- Handle truncation: snprintf returns the length it wanted to write; compare with the size.
int copy_name(char *dst, size_t dst_size, const char *src) {
size_t len = strlen(src);
if (len >= dst_size) return -1; /* would not fit: refuse */
memcpy(dst, src, len + 1); /* copy including '\0' */
return 0;
}Compiler and runtime protections
gcc -std=c17 -Wall -Wextra -O2 -D_FORTIFY_SOURCE=2 -fstack-protector-strong prog.c -o prog
gcc -std=c17 -g -fsanitize=address,undefined prog.c -o prog_test # while testing- -fstack-protector-strong places a "canary" value before the return address and aborts if it changes ("stack smashing detected").
- -D_FORTIFY_SOURCE=2 (needs optimisation, -O1 or higher) makes glibc check sizes in strcpy, memcpy and friends where the size is known at compile time.
- AddressSanitizer (-fsanitize=address) reports the exact line of any out-of-bounds read or write during testing (module 11).
- Operating-system defences (ASLR, non-executable stacks) make exploitation harder, but they do not fix the bug.
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
Buffer overflows and safe string handling · 1/6
In this lesson you will learn what buffer overflows are and how to prevent them.
Prefer a video by a teacher? Find free videos on “buffer overflow explained c stack smashing prevention” on YouTube ↗
In real life: A router firmware bug
Security researchers have repeatedly found home-router web interfaces that copy a form field (such as a device name) into a fixed-size stack buffer with strcpy. A long device name crashes the router, and a carefully crafted one can take it over. The fix in each case was simple: check the length and use a bounded copy.
/* vulnerable */
char devname[32];
strcpy(devname, form_value);
/* fixed */
if (strlen(form_value) >= sizeof devname) return HTTP_400_BAD_REQUEST;
memcpy(devname, form_value, strlen(form_value) + 1);Practice (0/3 done)
Which call can overflow buf (declared char buf[16])?
A program aborts with "*** stack smashing detected ***". What does it mean?
Take this function: void save_city(char *out, const char *in) { strcpy(out, in); }. Rewrite it as int save_city(char *out, size_t out_size, const char *in) that refuses (returns -1) when the input does not fit, and test it with a 10-byte buffer and inputs "Pune", "Thiruvananthapuram" and "". Then compile the ORIGINAL version with -fsanitize=address and call it with the long input to see the report.
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
- The <string.h> functionsStrings in C · same module
- Memory leaks and other heap bugsDynamic memory
- Sanitizers and warningsDebugging and tools
- Unsafe Rust: what it is and is notRust Programming · Testing, tooling and unsafe Rust
- Undefined behaviourBits, undefined behaviour and safety
- Classic C++ pitfalls in contests and coding roundsC++ Programming (modern C++ and DSA) · Competitive programming, interviews and careers
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 is a buffer overflow?
Answer: Writing past the end of an array into neighbouring memory
It corrupts other data.
Why is overwriting the return address dangerous?
Answer: It can redirect execution to an attacker's choice
Classic stack smashing.
What does -D_FORTIFY_SOURCE=2 need to work?
Answer: Optimisation (-O1 or higher)
The checks are added during optimisation.
Which is the best fix for an overflow found by a sanitizer?
Answer: Track sizes and use bounded functions with length checks
Fix the size handling.
Which tool is typically faster: valgrind or AddressSanitizer?Related
Should sanitizer builds be shipped to customers?Related
Answer: No; use them in development and testing
Ship normal hardened builds.
Does unsafe turn off the borrow checker?Related
Answer: No; it only allows five specific extra actions
References are still checked inside unsafe.
fgets returns NULL when…Related
Answer: End of input is reached (or an error occurs) before reading anything
Check it before using the buffer.
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
- This is the last topic of “Strings in C”. The module exam comes next.
- Module 4 exam: Strings in C · 12 questions · 25 min, without help. 5 topics of this module still to finish first.
- Then the next module, Pointers. 60 topics left in the course before the final exam.