Skip to content

Expert · Debugging and tools · topic 53 of 60 · 25 min

Sanitizers and warnings

Explanation

Sanitizers are compiler instrumentation that checks your program while it runs: AddressSanitizer (-fsanitize=address) finds out-of-bounds accesses, use-after-free and leaks; UndefinedBehaviorSanitizer (-fsanitize=undefined) finds signed overflow, bad shifts and more. They are much faster than valgrind. Combine them with strict warnings (-Wall -Wextra -Wpedantic -Wshadow -Wconversion) and static analysers to catch bugs before they ship.

AddressSanitizer (ASan)

bash
gcc -std=c17 -g -O1 -fsanitize=address -fno-omit-frame-pointer stock.c -o stock && ./stock
Works with gcc and clang on Linux and macOS (and MSVC has its own /fsanitize=address).
output
==7123==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60300000002c
WRITE of size 4 at 0x60300000002c thread T0
    #0 0x55d1… in restock stock.c:14
    #1 0x55d1… in main stock.c:31
0x60300000002c is located 0 bytes to the right of 12-byte region [0x603000000020,0x60300000002c)
allocated by thread T0 here:
    #0 0x7f3a… in malloc
    #1 0x55d1… in main stock.c:27
The program stops at the FIRST error, showing the bad access, the call stack and where the memory came from.

ASan reports heap-buffer-overflow, stack-buffer-overflow, global-buffer-overflow, heap-use-after-free, double-free, and (on Linux) memory leaks at exit. It typically slows a program down about 2× and increases memory use, which is acceptable for tests.

UndefinedBehaviorSanitizer (UBSan)

output
gcc -std=c17 -g -fsanitize=undefined calc.c -o calc && ./calc
calc.c:9:14: runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int'
calc.c:15:9: runtime error: shift exponent 32 is too large for 32-bit type 'unsigned int'
UBSan reports and (by default) continues; add -fno-sanitize-recover=all to stop at the first problem.

Use both together during development and testing: -fsanitize=address,undefined. ThreadSanitizer (-fsanitize=thread) finds data races in multithreaded code, but cannot be combined with ASan.

Warnings worth turning on

FlagCatches
-Wall -WextraThe common set: unused variables, missing returns, sign comparisons, format errors…
-WpedanticCode that is not strictly standard C
-WshadowA local variable hiding another with the same name
-WconversionImplicit conversions that may lose data (double → int, int → char)
-Wformat=2More printf/scanf format checks
-WerrorTreat all warnings as errors (keeps the build clean)

Static analysis

  • gcc -fanalyzer (GCC 10 and later): follows paths through your code and reports leaks, double frees, NULL dereferences and more, without running it.
  • clang-tidy: many checks, including bug-prone patterns and CERT C rules.
  • cppcheck: a free standalone analyser that is easy to start with.
  • Commercial tools (used in automotive and aerospace) check MISRA C and CERT C compliance.
Careful: Never ship sanitizer builds to production: they use more memory, change performance, and their extra checking runtime is not designed for hostile environments. Use them in development and CI; ship a normal optimised build with hardening flags (module 9).
Think of it like this: Warnings and static analysis are like proof-reading a letter before posting it; sanitizers are like a test drive with sensors fitted on every part of the car. You need both: one finds mistakes on paper, the other finds what goes wrong only while moving.
Tip: Add a "debug" target to your Makefile with -g -O1 -fsanitize=address,undefined and run your tests with it on every change. Most memory bugs then never reach a debugger.

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

Sanitizers and warnings · 1/6

Sanitizers and warnings

In this lesson you will catch bugs automatically with sanitizers, warnings and static analysis.

Prefer a video by a teacher? Find free videos on “addresssanitizer undefinedbehaviorsanitizer tutorial gcc fsanitize” on YouTube ↗

In real life: Catching an overflow in a CI pipeline

A company building a C library for parsing GST invoice files runs its test suite twice in CI: once normally and once with -fsanitize=address,undefined. A contributor's change passed the normal tests, but the sanitizer build failed with a stack-buffer-overflow on a long company name. The bug was fixed before it was ever released.

output
# Makefile fragment
test-asan:
	$(CC) -std=c17 -g -O1 -fsanitize=address,undefined -fno-omit-frame-pointer $(SRC) tests.c -o tests_asan
	./tests_asan

Practice (0/3 done)

Task 1 · Question

ASan reports "heap-use-after-free". What happened?

Task 2 · Question

Which sanitizer finds signed integer overflow?

Task 3 · Practice

Take the buggy programs from the valgrind and undefined-behaviour topics and build them with -g -fsanitize=address,undefined. Compare the reports with valgrind's (speed and detail). Then compile your best project with -Wall -Wextra -Wpedantic -Wshadow -Wconversion -fanalyzer and fix every warning.

Quick quiz

Question 1

1.Roughly how much does ASan slow a program down?

Question 2

2.Can ASan and ThreadSanitizer be used in the same build?

Question 3

3.What does -Wconversion warn about?

Question 4

4.Should sanitizer builds be shipped to customers?

Read more (free)

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.

Roughly how much does ASan slow a program down?

Answer: About 2×

Much faster than valgrind.

Can ASan and ThreadSanitizer be used in the same build?

Answer: No

Build them separately.

What does -Wconversion warn about?

Answer: Implicit conversions that may lose data

For example double to int.

Should sanitizer builds be shipped to customers?

Answer: No; use them in development and testing

Ship normal hardened builds.

Which tool is typically faster: valgrind or AddressSanitizer?Related

Answer: AddressSanitizer

ASan instruments at compile time.

From Memory leaks and other heap bugs

Which sanitizer finds use-after-free bugs?Related

Answer: AddressSanitizer

AddressSanitizer checks memory accesses.

From Building real projects: CMake, warnings, debuggers and sanitizers

Which is the best fix for an overflow found by a sanitizer?Related

Answer: Track sizes and use bounded functions with length checks

Fix the size handling.

From Buffer overflows and safe string handling

What does an exit status of 0 mean?Related

Answer: Success

Non-zero means failure.

From Compiling with gcc

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. 2 more topics in “Debugging and tools” before its exam: assert, logging and testing C code, A method for debugging.
  2. Module 11 exam: Debugging and tools · 12 questions · 25 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, Embedded C, system calls and careers. 60 topics left in the course before the final exam.

← Previous: Finding memory bugs with valgrind