Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

C++  Module 15 – Build systems, testing and tooling

Sanitizer and hardened C++ build presets

Build C++ in four CMake presets (ASan with UBSan, TSan, hardened and release), see which checks catch which bugs, and what each check costs.

  • Intermediate
  • 10 minutes
  • Examples run with Clang 21.0.0, GCC 16.2.0 and Python 3.14.8
  • By MySmartCoPilot
Free core, Pro depth: 4 of 10 minutes free
Free: Each build finds one family of bugs, at its own cost · Five bugs in four builds, and no build catches them all · A presets file names each build once, for every machine · Check yourself. With a pass: 2 in-depth parts and 3 interview answers, about 6 minutes.

What you will learn

  • Choose the build that finds each family of bugs, and state what each build costs
  • Distinguish the sanitizers that can share one build from those that need a build of their own
  • Read a bug matrix and tell sanitizer reports from library precondition checks
  • Write sanitizer and hardened presets in CMakePresets.json and run them as workflows
  • Pick a hardening mode for production from what it catches and what it costs

Before you start

What you’ll learn · Before you start

What you will learn

  • Choose the build that finds each family of bugs, and state what each build costs
  • Distinguish the sanitizers that can share one build from those that need a build of their own
  • Read a bug matrix and tell sanitizer reports from library precondition checks
  • Write sanitizer and hardened presets in CMakePresets.json and run them as workflows
  • Pick a hardening mode for production from what it catches and what it costs

Before you start

On this page

zoo.cpp holds five bugs, and its release build ran all five to the end, printing “finished” every time. A sanitizer: A compiler option, such as -fsanitize=address or -fsanitize=undefined, that builds extra checks into a program, so that memory errors and undefined behaviour are reported, with their source line, while it runs. More in “Finding memory bugs with AddressSanitizer and UBSan” build compiles the program with run-time checks for one family of bugs, and a hardened build keeps only the checks that are cheap enough to ship. Sanitizer and hardened C++ build presets give each of those builds a name in CMakePresets.json, so that everyone and the continuous-integration server build them the same way. The usual set has four: asan-ubsan for memory errors and undefined behaviour: What a program does when it breaks a rule for which the C++ standard sets no requirements, such as reading past the end of an array. The compiler may assume it never happens, so the result can change with the compiler and the optimisation level. More in “Object lifetime and undefined behaviour in C++”, tsan for data races, hardened for the standard library’s precondition checks, and release for timing and shipping. ASan and UBSan can share one build; ThreadSanitizer needs a build of its own, because it cannot be combined with AddressSanitizer.

Each build finds one family of bugs, at its own cost

Preset Flags with Clang or GCC Finds Cost
asan-ubsan -O1 -g -fsanitize=address,undefined -fno-sanitize-recover=all -fno-omit-frame-pointer Memory errors, signed overflow, bad shifts and indexes About 2× the time, says Clang’s ASan documentation
tsan -O1 -g -fsanitize=thread Data races between threads 5× to 15× the time and 5× to 10× the memory, for TSan
hardened libc++: -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST; GCC on Linux: -fhardened Misuse of the standard library, such as an index past the end Small, by design
release -O2 Nothing None

-fno-sanitize-recover=all matters in a test preset: without it most UBSan checks recovery (sanitizers): What most UndefinedBehaviorSanitizer checks do by default after a report: they print it and let the program go on, so a test can pass with errors in its output. -fno-sanitize-recover=all makes the first report end the program., so a test can pass with errors in its output. The two sanitizer presets are for tests and CI only. The hardened preset is the one meant for production: libc++ recommends its fast mode for most projects, and -fhardened is GCC’s bundle of security options for release builds. A common split runs asan-ubsan and tsan on every change, the hardened preset in the release pipeline and in production, and the plain release preset only for benchmarks.

Checkpoint

Check: Four builds and what each one finds

  1. Question 1 of 2 Which of the four presets is the one meant to ship to production?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: hardened

    The two sanitizer presets are for tests and CI only. The hardened preset keeps the checks that are cheap enough to ship, which makes it the production build; release is for benchmarks.

  2. Question 2 of 2 A test in an ASan and UBSan build prints "runtime error: signed integer overflow" and still passes. Which flag is missing from that build?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: -fno-sanitize-recover=all

    The report shows that UBSan found the overflow. It is -fno-sanitize-recover=all that turns the first report into the end of the program, with a failing status, so the test fails as it should.

AddressSanitizer and ThreadSanitizer never share a build

  • AddressSanitizer and UndefinedBehaviorSanitizer work together, and on Linux ASan also brings LeakSanitizer.
  • ThreadSanitizer cannot be combined with AddressSanitizer or LeakSanitizer, so it gets its own build.
  • MemorySanitizer, Clang’s check for reads of uninitialised memory on Linux, needs a build of its own too.
  • hardened standard library: A standard library that checks the preconditions of calls such as operator[] and front() while the program runs, and stops it when one fails, as libc++'s hardening modes and libstdc++ with _GLIBCXX_ASSERTIONS do. C++26 makes such hardened implementations part of the standard. More in “std::vector: the container to reach for first” is ordinary code in the library headers, so it combines with any of them.

The diagram shows the three sanitizer builds this leaves, and the one kind of check that fits into all of them:

Three sanitizer builds that cannot be merged into one, and standard library hardening, which combines with each of them.Standard library hardeningcode in the library headersNever merged into one buildasan-ubsan buildAddressSanitizer + UBSan(+ LeakSanitizer on Linux)tsan buildThreadSanitizer alonemsan build (Clang, Linux)MemorySanitizer alonefits into each

Which checks can share one build

Text description of the diagram

At the top, a box for standard library hardening, which is code in the library headers. An arrow labelled "fits into each" leads from it to a group of three sanitizer builds that are never merged.

  1. The asan-ubsan build holds AddressSanitizer and UndefinedBehaviorSanitizer together, and on Linux AddressSanitizer brings LeakSanitizer too.
  2. The tsan build holds ThreadSanitizer alone: it cannot be combined with AddressSanitizer or LeakSanitizer.
  3. The msan build holds MemorySanitizer alone, Clang's check for reads of uninitialised memory on Linux.

Hardening can be added to any of the three builds, and to a release build, because it is ordinary code in the headers of the standard library.

Checkpoint

Check: Sanitizers that can share a build

  1. One question Besides ThreadSanitizer, which check needs a build of its own?

    Choose one answer.

    Show the answer: One question

    Answer: MemorySanitizer

    The checks leave three sanitizer builds: asan-ubsan (with LeakSanitizer on Linux), tsan, and msan with Clang on Linux. Hardening fits into each of them, as the diagram shows.

Five bugs in four builds, and no build catches them all

zoo.cpp holds five bugs, and the command line chooses one:

zoo.cpp C++ · zoo.cpp
// Five bugs, chosen by name on the command line; each check catches only some of them.
#include <climits>
#include <optional>
#include <print>
#include <string>
#include <string_view>
#include <thread>

volatile int sink;  // reads go here, so the optimiser keeps them

void view_past_end() {
    std::string_view code = "IN-KA";
    sink = code[5];  // one past the last character
}

void empty_optional() {
    std::optional<int> port;  // nothing was stored
    sink = *port;
}

void array_past_end(int i) {
    int scores[4] = {70, 82, 91, 64};
    sink = scores[i];  // called with i == 4
}

void signed_overflow(int n) {
    sink = n + 1;  // called with n == INT_MAX
}

void data_race() {
    int hits = 0;
    auto count = [&hits] { for (int k = 0; k < 100000; ++k) ++hits; };
    std::thread a(count), b(count);  // both threads write hits
    a.join();
    b.join();
    sink = hits;
}

int main(int argc, char** argv) {
    const std::string bug = argc > 1 ? argv[1] : "";
    if (bug == "view") view_past_end();
    else if (bug == "optional") empty_optional();
    else if (bug == "array") array_past_end(argc + 2);
    else if (bug == "overflow") signed_overflow(INT_MAX - 2 + argc);
    else if (bug == "race") data_race();
    else return 2;
    std::println("{}: finished", bug);
}

Here is each bug in each build, compiled with the flags of the presets above by Apple clang on a Mac:

Five bugs in four builds Python · matrix_session.py
"""Builds zoo.cpp with the flags of each preset of this lesson, runs each of its five bugs in each build, and prints
one line per run: the first line of the report that stopped it, or that it finished with nothing reported."""

import signal
import subprocess

from session import run, tool_env

PRESETS = {
    "release": "-O2",
    "asan-ubsan": "-O1 -g -fsanitize=address,undefined -fno-sanitize-recover=all -fno-omit-frame-pointer",
    "tsan": "-O1 -g -fsanitize=thread",
    "hardened": "-O2 -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST",
}
BUGS = ["view", "optional", "array", "overflow", "race"]
MARKERS = ["runtime error:", "ERROR: AddressSanitizer:", "WARNING: ThreadSanitizer:"]


def outcome(result: subprocess.CompletedProcess) -> str:
    """What stopped a run, in a few words."""
    if result.returncode == 0:
        return "finished, nothing reported"
    for line in result.stdout.splitlines():
        for marker in MARKERS:
            if marker in line:
                return line[line.index(marker):].split(" (pid=")[0]
    if result.returncode < 0:
        return f"stopped by {signal.Signals(-result.returncode).name}, no message"
    return f"exit status {result.returncode}"


run("\n".join(f"clang++ -std=c++23 {flags} zoo.cpp -o zoo-{name}" for name, flags in PRESETS.items()))
print()
for name in PRESETS:
    for bug in BUGS:
        result = subprocess.run([f"./zoo-{name}", bug], env=tool_env(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
        print(f"{name:<11} {bug:<9} {outcome(result)}")

Output

$ clang++ -std=c++23 -O2 zoo.cpp -o zoo-release
$ clang++ -std=c++23 -O1 -g -fsanitize=address,undefined -fno-sanitize-recover=all -fno-omit-frame-pointer zoo.cpp -o zoo-asan-ubsan
$ clang++ -std=c++23 -O1 -g -fsanitize=thread zoo.cpp -o zoo-tsan
$ clang++ -std=c++23 -O2 -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST zoo.cpp -o zoo-hardened

release     view      finished, nothing reported
release     optional  finished, nothing reported
release     array     finished, nothing reported
release     overflow  finished, nothing reported
release     race      finished, nothing reported
asan-ubsan  view      finished, nothing reported
asan-ubsan  optional  finished, nothing reported
asan-ubsan  array     runtime error: index 4 out of bounds for type 'int[4]'
asan-ubsan  overflow  runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int'
asan-ubsan  race      finished, nothing reported
tsan        view      finished, nothing reported
tsan        optional  finished, nothing reported
tsan        array     finished, nothing reported
tsan        overflow  finished, nothing reported
tsan        race      WARNING: ThreadSanitizer: data race
hardened    view      stopped by SIGTRAP, no message
hardened    optional  stopped by SIGTRAP, no message
hardened    array     finished, nothing reported
hardened    overflow  finished, nothing reported
hardened    race      finished, nothing reported

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 matrix_session.py

No build caught everything. The release build caught nothing: all five runs printed “finished”. asan-ubsan stopped the two bugs that are undefined behaviour of the language, the array index and the signed overflow; UBSan reported first because the array’s bound is known at compile time. tsan found only the Two threads reach the same memory at the same time, at least one of them writing, with nothing that orders the two accesses. In C++ that is undefined behaviour, and ThreadSanitizer reports it.. hardened stopped the string_view read and the empty optional, which both sanitizers missed: the memory they read was valid, so nothing was wrong at the level of bytes, only at the level of the library’s preconditions. That is why a project needs both kinds of build, and why the matrix runs every test in each of them.

Here are the twenty runs again, as a table that rules out builds by the job they do:

Interactive · answer and compare Which build stops which bug in the zoo? Answer two questions about the job a build does. The table rules out the builds that do not fit, and every cell shows what the recorded run printed.
What is the build for?
Does the code under test start threads?

Answer the questions above: the table then marks what fits your case and says why the rest does not.

Four builds of zoo.cpp against its five bugs, as the recorded matrix ran them
Build string_view read past its end Empty optional read C array index past its end Signed integer overflow Data race between threads
release Checks: nothing: -O2 only Poor finished, nothing reported Poor finished, nothing reported Poor finished, nothing reported Poor finished, nothing reported Poor finished, nothing reported
asan-ubsan Checks: memory errors and undefined behaviour Poor finished: the byte it read was valid memory Poor finished: an empty optional still holds its storage Good runtime error: index 4 out of bounds for type 'int[4]' Good runtime error: signed integer overflow: 2147483647 + 1 Poor finished, nothing reported
tsan Checks: data races between threads Poor finished, nothing reported Poor finished, nothing reported Poor finished, nothing reported Poor finished, nothing reported Good WARNING: ThreadSanitizer: data race
hardened Checks: the standard library's preconditions Good stopped by SIGTRAP, no message Good stopped by SIGTRAP, no message Poor finished: a C array has no library check Poor finished: arithmetic is not a library call Poor finished, nothing reported
How the answers decide
  • “What is the build for?” Shipping to production: rules out asan-ubsan and tsan. Sanitizer builds are for tests and CI. Clang's documentation puts ASan at about 2× the time and TSan at 5× to 15× the time and 5× to 10× the memory.
  • “What is the build for?” Shipping to production: adds a caveat to release. A release build ships, but it stopped none of the five bugs. The hardened build is the one meant for production.
  • “What is the build for?” Running the tests on every change: adds a caveat to release. The release build stopped nothing in the zoo. Keep it for timing and benchmarks, and run the tests in the other builds.
  • “Does the code under test start threads?” Yes, it uses threads: adds a caveat to asan-ubsan and hardened. Only tsan stopped the race. Code that starts threads runs its tests in a tsan build as well.
  • “Does the code under test start threads?” No, one thread only: adds a caveat to tsan. With one thread there is no race for tsan to find; asan-ubsan and hardened together stopped the other four bugs.

Key idea

Sanitizers find bugs in bytes and in the rules of the language; hardening finds misuse of the library.

Checkpoint

Check: Bytes against library preconditions

  1. Question 1 of 2 In the recorded matrix, which build stopped the read past the end of the C array scores?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: asan-ubsan

    An index past the end of int scores[4] is undefined behaviour of the language, which is the asan-ubsan build's job. The hardened build checks the standard library's preconditions, and a C array has none.

  2. Question 2 of 2 Why did the hardened build stop the string_view read past its end, while the asan-ubsan build let it finish?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: The byte it read was valid memory; only string_view's precondition, an index below its size, was broken

    Sanitizers find bugs at the level of bytes and the rules of the language. A string_view that reads one character past its end still reads valid memory, so only a check of the library's own precondition can stop it.

A presets file names each build once, for every machine

  • Configure presets set the generator, the build folder and cache variables such as CMAKE_CXX_FLAGS.
  • A hidden preset holds shared settings; other presets copy them with inherits.
  • Build and test presets name a configure preset; test presets add options and environment variables.
  • A workflow preset (CMake): A preset in CMakePresets.json that runs other presets in order, such as configure, build and test, so that one command, cmake --workflow --preset name, does all of them. runs configure, build and test in one command: cmake --workflow --preset asan-ubsan.
  • A condition limits a preset to one system, for example -fhardened presets to Linux.

Step through what that one command does with the presets it names:

Interactive · stage by stage One command, three presets, one build Step through cmake --workflow --preset asan-ubsan. Each stage is one kind of preset from the list above, in the order CMake uses them.
One command, three presets, one build, step 5 of 5. Showing Workflow preset, Configure preset, Build preset, Test preset, Conditions. In focus: Conditions.Workflow presetasan-ubsan: three stepsConfigure presetgenerator, folder, flagsBuild presetnames its configure presetTest presetruns the tests of that buildConditionsa preset only where it works

The drawing shows the whole scene; its 5 steps are listed below.

Every step as text
  1. One command. cmake --workflow --preset asan-ubsan reads CMakePresets.json and finds the workflow preset named asan-ubsan. It lists three steps, configure, build and test, each by the name of another preset.
  2. Configure. The configure preset copies the generator and the build folder from a hidden preset with inherits, and sets CMAKE_CXX_FLAGS to the asan-ubsan flags of the first table, -fno-sanitize-recover=all included.
  3. Build. The build preset names the configure preset it builds, so the compiler gets exactly those flags. Nobody types them again, on a laptop or on the CI server.
  4. Test. The test preset runs the tests of that build and adds its own options and environment variables. With -fno-sanitize-recover=all in the flags, a UBSan report ends the program and fails its test.
  5. Only where it works. A condition limits a preset to one system. A preset with GCC's -fhardened can be limited to Linux, so that the same file also works on a Mac.

Because the flags live in the file, the same command gives a laptop and a CI server the same build. With hardened C++ build presets beside the sanitizer ones, a release can keep cheap checks while the tests run every expensive one.

Checkpoint

Check: What a presets file holds

  1. One question Which single command configures, builds and tests the asan-ubsan build?

    Choose one answer.

    Show the answer: One question

    Answer: cmake --workflow --preset asan-ubsan

    Configure, build and test presets each name one step. A workflow preset strings them together, so cmake --workflow --preset asan-ubsan does all three.

Check yourself

Eleven questions on the four builds, the checks that share one, the bug zoo and the presets file, weakest idea first, with a reason for every choice.

Practice that adapts to you

Practise this lesson

11 questions about 7 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 11 A test sometimes fails when two threads update a shared counter. Which preset is built to find that bug?

    Choose one answer.

    Show the answer: Question 1 of 11

    Answer: tsan

    ThreadSanitizer reports data races, and in the bug zoo only the tsan build stopped the race. AddressSanitizer and the hardened library check memory and library preconditions, not the ordering of two threads' writes.

  2. Question 2 of 11 Why does the asan-ubsan preset pass -fno-sanitize-recover=all?

    Choose one answer.

    Show the answer: Question 2 of 11

    Answer: Without it most UBSan checks print a report and let the program continue, so a test can still pass

    UBSan recovers by default, and a test that only prints a report still passes. With -fno-sanitize-recover=all the first report ends the program with a failing status, so the test fails.

  3. Question 3 of 11 A project has the four presets of this lesson. Which plan runs each build where it belongs?

    Choose one answer.

    Show the answer: Question 3 of 11

    Answer: asan-ubsan and tsan on every change, hardened in the release pipeline and in production, release only for benchmarks

    Run the expensive checks where only time is at stake, on every change in CI, ship the cheap checks in the hardened build, and keep the unchecked release build for measuring speed.

  4. Question 4 of 11 Which of these pairs can share one build?

    Choose every answer that is right.

    Show the answer: Question 4 of 11

    Answer:

    • AddressSanitizer and libc++'s fast hardening mode
    • AddressSanitizer and UndefinedBehaviorSanitizer

    ASan and UBSan are the usual pair, and hardening is code in the library headers, so it works with any sanitizer. GCC refuses -fsanitize=thread together with -fsanitize=address, and Clang refuses MemorySanitizer with ASan.

  5. Question 5 of 11 Can AddressSanitizer and ThreadSanitizer check the same build?

    Choose one answer.

    Show the answer: Question 5 of 11

    Answer: No, the compilers refuse the combination, so each gets its own build

    Both sanitizers bring their own run-time library, and the two cannot share one process. A project therefore keeps an asan-ubsan build and a separate tsan build.

  6. Question 6 of 11 You add -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST to the tsan build of a project on macOS. What happens?

    Choose one answer.

    Show the answer: Question 6 of 11

    Answer: It builds, and the tests now run with ThreadSanitizer and the library's checks together

    The diagram's top box fits into each sanitizer build: hardening is code in the headers, so the tsan build can carry it too, and its tests then check races and library preconditions at once.

  7. Question 7 of 11 In the bug zoo, *port read an empty std::optional<int>. Why did the asan-ubsan build let it finish?

    Choose one answer.

    Show the answer: Question 7 of 11

    Answer: The bytes it read belong to a live object, so nothing was wrong at the memory level; only the library's precondition was broken

    An empty optional still holds its storage, so reading it touches valid memory and ASan has nothing to report. The broken rule is the library's precondition has_value(), which only a hardened library checks.

  8. Question 8 of 11 How many of the zoo's five bugs did the release build stop?

    Type a number.

    Show the answer: Question 8 of 11

    Answer: 0 bugs

    None: all five release runs printed "finished". That is why a test suite that passes in the release build alone proves nothing about these bugs.

  9. Question 9 of 11 Your tests pass in the release and asan-ubsan builds, but the hardened build stops one of them with a trap and no message. What kind of bug is it most likely?

    Choose one answer.

    Show the answer: Question 9 of 11

    Answer: A call that breaks a library precondition on valid memory, like the zoo's empty optional

    Each build sees one family of bugs. A trap in the hardened build, with ASan silent, matches the string_view and optional bugs of the zoo: valid bytes, broken library preconditions.

  10. Question 10 of 11 What does a condition in a preset do?

    Choose one answer.

    Show the answer: Question 10 of 11

    Answer: It limits the preset to the systems where it can work, such as -fhardened presets to Linux

    One presets file then works on every system: each machine sees the presets that make sense there, and the commands stay the same.

  11. Question 11 of 11 Two developers and the CI server must build asan-ubsan with exactly the same flags. Where do the flags belong?

    Choose one answer.

    Show the answer: Question 11 of 11

    Answer: In CMAKE_CXX_FLAGS, in the cache variables of the asan-ubsan configure preset in CMakePresets.json

    The point of a presets file is that a build has one name and one set of flags. The configure preset holds the flags once, and every command that names the preset uses them.

A CMakePresets.json for the four builds, run end to end Pro: opens with a Pro, Premium or Ultimate pass

Writing the four builds as presets turns a list of flags into one command per build. This part walks through a complete presets file and runs every workflow on Linux, with the test results each one produced.

In this part:

  • The presets file, part by part
  • Every workflow on Linux, with its test results
  • Wiring the presets into CI

2 runnable examples (CMakeLists.txt, CMakePresets.json, Text) · about 4 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Hardening for production: what each mode catches and costs Pro: opens with a Pro, Premium or Ultimate pass

Production hardening is a trade: every check costs a little time and turns a silent bug into a stopped program. This part measures both sides on one program, compares libc++’s modes with GCC’s options, and shows where C++26 takes it.

In this part:

  • What fast, extensive and debug mode each catch, reproduced
  • The cost of each check, measured
  • GCC’s -fhardened, MSVC and the C++26 hardened implementation

6 runnable examples (C++, Python, Text) · about 6 minutes

Opening this part with your pass…Pro part. It opens with the same pass as the part above.

Interview questions

  1. Fresher to mid · Warm-up

    Why do AddressSanitizer and ThreadSanitizer need separate builds?

    Both instrument every memory access and bring their own run-time library, which replaces parts of the normal run-time, such as the memory allocator, with versions that do their bookkeeping. The two designs cannot share one process, so the compilers refuse the combination outright: GCC says that -fsanitize=thread is incompatible with -fsanitize=address, and Clang rejects it too. A project therefore keeps two sanitizer builds: one with ASan and UBSan, which do combine, for memory errors and undefined behaviour, and one with TSan for data races, run on the tests that use threads. MemorySanitizer, Clang's check for uninitialised reads, also needs its own build.

  2. Mid to senior

    Your team wants to ship a C++ service with standard library hardening, but the latency budget allows at most 3 % more CPU. A benchmark shows libc++'s fast mode costing 12 % in one hot loop and nothing measurable elsewhere. What do you ship, how do you measure it, and what do you change?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  3. Mid to senior

    After an out-of-bounds crash in production, a teammate proposes shipping the AddressSanitizer build of the service from now on, "so that the next bug is caught". Evaluate the idea and propose what you would ship instead.

    Model answer, Pro. First step and follow-ups

  4. Fresher to mid

    After the team moves to GCC 15, a debug build that worked for years aborts in a test with "Assertion '__n < this->size()' failed" inside std::vector. The release build still passes. Is the new compiler wrong, and what do you do?

    Model answer, Pro. First step and follow-ups

Key takeaways

  • Give each build a preset: asan-ubsan and tsan for tests, hardened for production, release for timing.
  • ASan and UBSan share a build; TSan and MSan need builds of their own.
  • Sanitizers find bugs in bytes; hardening finds misuse of the library; a release build finds neither.
  • Add -fno-sanitize-recover=all to test builds, so that every report fails the run.

Terms in this lesson

recovery (sanitizers)
What most UndefinedBehaviorSanitizer checks do by default after a report: they print it and let the program go on, so a test can pass with errors in its output. -fno-sanitize-recover=all makes the first report end the program.
workflow preset (CMake)
A preset in CMakePresets.json that runs other presets in order, such as configure, build and test, so that one command, cmake --workflow --preset name, does all of them.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.