Introduction
A C compiler trusts you. When a program breaks a rule, such as reading past an array, the C standard says the behaviour is undefined: anything may happen. Often the program seems to work, then fails later, on another computer, or in an exam.
StepVioz checks for these bugs while it runs your program, and stops at the exact line. Here is the list to remember:
| Bug | Real C | Fix |
|---|---|---|
| Reading an uninitialized variable | prints garbage | give it a value first |
| Index past the end of an array | changes other variables | loop with i < n |
int overflow | wrong number, no warning | use long long |
Following NULL | crash (segmentation fault) | check p != NULL |
Using memory after free | random crash, maybe much later | set the pointer to NULL |
| Freeing twice | crash or corrupt heap | free each block exactly once |
String without room for '\0' | reads or writes past the end | one extra byte for '\0' |
scanf without & | crash | scanf("%d", &n) |
Wrong printf format | prints nonsense | %d int, %f double, %s string |
| Returning the address of a local | dangling pointer | return a value, or use malloc |
In many languages a mistake produces a clear error. In C it may produce a wrong number, a crash an hour later, or nothing at all until the program is moved to another computer. Knowing these bugs by name is one of the most valuable things this course can give you.
How it works
Try them
Each line of this program has one of the bugs. Run it, read the message, fix that line, and run again until it reaches the end:
#include <stdio.h>
int main(void) {
int count;
int total = 0;
int values[3] = {4, 5, 6};
for (int i = 0; i <= 3; i++) {
total += values[i];
}
count = count + 1;
printf("%d %d\n", total, count);
return 0;
}Why StepVioz stops when C would not
A compiled C program cannot afford to check every step; StepVioz runs your code more slowly in exchange for catching these bugs. Code that runs cleanly here can still behave differently with another compiler only in the few places where C itself leaves the result up to the compiler (such as the size of long).
Syntax
gcc -Wall -Wextra -g program.c -o program
gcc -fsanitize=address -g program.c -o program
Example
Here is the program from above with its two bugs fixed: count is given a first value, and the loop stops before it goes past the end.
#include <stdio.h>
int main(void) {
int count = 0;
int total = 0;
int values[3] = {4, 5, 6};
for (int i = 0; i < 3; i++) {
total += values[i];
}
count = count + 1;
printf("%d %d\n", total, count);
return 0;
}Line by line
int count = 0;gives the variable a value before it is used.valueshas three elements, at indexes 0, 1 and 2.- The loop runs while
i < 3, so it never goes past the end. count = count + 1now reads a real value.printfshows the total of 15 and the count of 1.
Expected result
15 1
In the real world
Memory-safety bugs of these kinds make up a large share of serious security problems in big C and C++ programs. That is why compilers offer sanitizers, and why careful teams run them on every change.
Common mistakes
- Assuming that a program is correct because it printed the right answer once.
- Ignoring compiler warnings.
- Changing code at random until the symptom goes away.
Best practices
- Compile with
-Wall -Wextra, and fix every warning. - Use a sanitizer while developing.
- Reduce a bug to the smallest program that still shows it.
Summary
C trusts the programmer, so mistakes such as overruns, uninitialised values and use after free may fail silently. Warnings, sanitizers and careful habits catch these bugs. StepVioz checks for them as your program runs.
Quick check
Key takeaways
- A C program that seems to work may still be wrong.
- Turn on compiler warnings and read them.
- StepVioz catches these bugs at the exact line.
Practice problems for this lesson
My notes
Write down what you want to remember from this lesson. Notes are saved on this device as you type, and appear on your dashboard.