Skip to content

Warnings, Sanitizers, and Static Analysis

Native correctness needs overlapping evidence. Compilers can warn about suspicious source, sanitizers detect instrumented runtime violations, static analyzers explore paths, and tests decide whether behavior matches intent.

Establish a warning-clean baseline

For GCC/Clang course examples:

sh
-Wall -Wextra -Wpedantic

Projects often add conversion, shadowing, format, missing-prototype, or switch warnings selectively. C and C++ need different profiles. MSVC /W4 is a strong application baseline. Promote project warnings to errors in CI after the baseline is clean, while treating external headers separately.

Warnings are implementation diagnostics, not standardized proof. New compiler releases add warnings, so pin or stage upgrades rather than letting -Werror surprise releases.

Sanitizers instrument executable behavior

AddressSanitizer detects many out-of-bounds, use-after-free, and stack lifetime errors:

sh
c++ -fsanitize=address -fno-omit-frame-pointer -g source.cpp -o app

UndefinedBehaviorSanitizer checks many invalid operations:

sh
c++ -fsanitize=undefined -g source.cpp -o app

AddressSanitizer and UndefinedBehaviorSanitizer can be combined on many compiler/platform configurations, but supported combinations vary. Compile and link with consistent sanitizer flags, run meaningful tests, and preserve symbolization.

ThreadSanitizer detects data races but has higher overhead and generally cannot be combined with AddressSanitizer in one binary. Run a separate configuration. MemorySanitizer detects uninitialized reads but requires a substantially instrumented dependency environment and is mainly a Clang-oriented specialized setup.

MSVC supports AddressSanitizer for documented target/toolset combinations. Use official support matrices rather than assuming every Unix flag translates.

Valgrind retains a useful niche

Valgrind's Memcheck can inspect uninstrumented or lightly prepared binaries on supported platforms, at high runtime cost. It remains useful where available, especially for leak and invalid-access diagnostics. It is not a universal macOS/Windows replacement for compiler sanitizers.

Static analyzers explore without executing

Clang Static Analyzer, clang-tidy checks, GCC's analyzer, MSVC code analysis, and commercial tools detect path and pattern problems. Configure analyzers with the actual compile commands so macros, include paths, and language modes match.

clang-tidy includes bug-prone, performance, portability, and modernization checks. Enabling an entire check family blindly produces noise and risky mechanical rewrites. Select checks, baseline existing findings, and review fixes as code changes.

Findings need triage, not suppression reflexes

For each warning:

  1. understand the path and language rule;
  2. fix the underlying contract when possible;
  3. use a narrow documented suppression only for a proven false positive;
  4. keep third-party suppressions outside first-party policy;
  5. add a regression test when behavior is observable.

Casts, NOLINT, and warning-disable flags can hide evidence; they are not fixes by themselves.

Optional prompts

Explain: Why does a clean sanitizer run not prove memory safety?

Answer: It covers only executed paths, detectable violation classes, and that build/platform. It is strong dynamic evidence, not proof over all inputs and executions.

Explain: Why might ASan and TSan use separate CI jobs?

Answer: Their instrumentation is expensive and generally incompatible in one binary; each detects a different class of runtime defect.

Further reference