Skip to content

Symptom Index

Symptom Index

Real problems do not arrive labelled with the chapter that owns them; they arrive as something on a screen. The ticket chapters (32–37) are titled as their symptoms and every entry in the Gotchas (Chapter 25) opens with one; this page routes the rest of the book the same way, from what you see to where it is taught.

What you see Where it is taught
A crash after main returns — __cxa_finalize or atexit in the stack Chapter 32
Works in Debug, breaks in Release Chapter 3, Chapter 13, and Chapter 31's -O2 section
undefined reference / Undefined symbols / LNK2019 Chapter 12, Chapter 23; the sanitizer-runtime variant, Chapter 26
multiple definition / duplicate symbol / LNK2005 Chapter 12, Chapter 23; two versions of one library, Chapter 27
A watched value goes wrong after a container grows Chapter 11, Chapter 21, Chapter 33
The host says objects are still live at shutdown Chapter 17, Chapter 35
A crash inside a callback, or after the callback's owner died Chapter 18, Chapter 22, Chapter 29
Garbage — or mirrored — values decoded from a wire or a file Chapter 34
Sanitizers green, values wrong Finding 10 in Chapter 25, Chapter 34
No leak report on a Mac that should have one Chapter 31's leak section, and Finding 10 in Chapter 25
Non-ASCII text corrupts, or a string's length looks wrong Chapter 9, Recipe 17 in Appendix F
-858993460 or 0xcccccccc in a variable Chapter 3
It broke when the library added a private member Chapter 27, Chapter 30
The process died in CI and the log is empty Chapter 28, Recipe 15 in Appendix F
Stutter, dropouts, or frame spikes with your code loaded — but the profile says you are cheap Chapter 36
Text is fine for most customers and mojibake for the German and Russian ones Chapter 39, Chapter 9
A managed caller crashes inside your library, and the managed stack looks fine Chapter 39
A crash report full of raw addresses, or a fault address just past null Chapter 37
A client of your plug-in shows a spinner forever — or the host freezes with one thread parked in a wait Chapter 38
A profile in which every function is called from nowhere, or that is a column of addresses Chapter 31's profiler section, Chapter 37
Runs from the build tree, dies before main installed or on the customer's machine — dyld: Library not loaded, error while loading shared libraries, X.dll was not found Appendix J's runtime-delivery entry; the sanitizer-runtime variant in Chapter 26
A crash on entry to a function, before its first line — stack-overflow, or a bare SEGV/BUS "on unknown address": one stack, and no allocation site Chapter 3, Recipe 34 in Appendix F; when the recursion is the user's text — a pasted formula — Chapter 42's depth guard
A saved file is empty or truncated after a crash — the customer's preferences are gone (after a power cut, the same symptom needs the fsync that recipe names) Recipe 38 in Appendix F
A file watcher fires once and then never again — or misses a second save made within the same second Recipe 40 in Appendix F: an editor saved by rename (Recipe 38), or a timestamp at the filesystem's resolution
curl_easy_perform returned CURLE_OK and the body is an HTML error page — the JSON parse fails and "the server is flaky" Recipe 41 in Appendix F: two verdicts, the transport's and the server's, and only one was checked
sqlite3_close returns SQLITE_BUSY at shutdown — or, if the leaked statement was a SELECT abandoned mid-rows, the file stays read-locked after the plug-in unloads Recipe 42 in Appendix F: a statement nobody finalized — Chapter 35's still-live-at-unload, one library over
A struct read from shared memory is garbage on the other side — or a region is still there after every process that used it has exited Recipe 43 in Appendix F and Chapter 34: the layout was the compiler's, not a document's; and nobody unlinked the name
__cplusplus reads 199711 on a compiler that plainly speaks C++17 — or -std=c++23 is accepted and <expected> is still not found Appendix K: MSVC's /Zc:__cplusplus, and the feature-test macro that asks the library rather than the switch
A trimmed or matched substring reads as garbage a few lines later — or the per-sample path stutters and there is a pattern match on it Recipes 44 and 45 in Appendix F: a view or a match_results into a string that has died; std::regex on the deadline path
The server logs a request body that is empty, or garbage, while the client swears it sent JSON — or the reply parsed and the field the code needs is not in it Recipe 46 in Appendix F: CURLOPT_POSTFIELDS borrows the bytes and a temporary died at the semicolon; the three verdicts, and at() for the key that must be there
open_sealed on one side returns nullopt for every envelope the other side sealed, after a config change and with no error anywhere — or a review comment asks why two tags are compared with == Recipes 47 and 48 in Appendix F: the iteration count and salt are part of the key; == on a tag leaks by timing, CRYPTO_memcmp does not
A formula gives the right answer on every developer's machine and a different one on a customer's — 1,5 read as one and a half, or 1.5 as one Chapter 42: strtod reads the host's locale; from_chars asks none
A process reading one file uses as much memory as the file — or, on Linux, dies with SIGBUS on a plain read, no allocation site, none of the shapes above, after another process truncated the file it had mapped Recipe 49 in Appendix F: map it rather than copy it, and map only what nobody else writes
A rounded total disagrees with the C# service's by one, on halves only — 2.5 became 3 where the report says 2 Recipe 52 in Appendix F: Math.Round rounds halves to even and std::round rounds them away from zero
A negative value is off by one after a conversion — -2.7 became -2 where the chart wanted -3 Recipe 52 in Appendix F: a cast truncates toward zero, floor goes down, and they disagree on every negative
An argument's side effect happened twice, or an if ran half of something it should not have run at all Chapter 12: a macro substitutes text, so an argument appears as many times as it is written and two statements are not one
std::max or std::min stops compiling after a header is added, with the error inside the standard library Chapter 12: <windows.h> defines them as macros, and a macro has no namespace to be qualified out of — NOMINMAX before the include
Two threads doing unrelated work are slower together than either alone, and no lock appears in the profile Appendix L: false sharing — two variables inside one cache line, which never appears in a profile as itself
A licence or token file verifies perfectly on a machine it was never issued for Recipe 54 in Appendix F: a signature proves who wrote the bytes and nothing else; what must not be replayed goes inside them
An audio, render or control callback misses its deadline every few minutes, and the profile shows a lock or a push_back on that thread rather than an allocation of yours Chapter 43: a lock on a deadline thread waits for whichever thread holds it — the hand-off is a bounded ring with one producer and one consumer, never a mutex
A lock-free ring delivers a sample that is exactly one lap old — the index advanced and the slot did not — on an arm64 machine, and never on x86-64 Chapter 43: the store that publishes must be release and the load that consumes acquire; relaxed is no ordering at all, and one instruction set hides that
A signal handler, interrupt callback or driver-context callback stops the process cold, and every sanitizer sits there with it Chapter 43: a lock taken in interrupt context is held by the code it interrupted — one thread, waiting for itself
A crash when the host closes a document or a window, with your destructor on the access stack and the framework's own teardown on the freed by stack — and a bench that cannot reproduce it because it unloads first Chapter 44: a unique_ptr on a node the framework's parent already owns — two owners, and the host's order decides which pays second
A framework-owned object's handle dangles after the window or document is gone, or a node that never got a parent leaks Chapter 44: hold what the framework owns through its own weak handle; own a node only until you hand it over, and release on that line
A class that has worked for years dies the first time someone copies it — heap-use-after-free in its destructor or its Clear, freed by its own growth in the other copy Chapter 45: the compiler-generated copy of an owning class is a shallow one; declare it deleted first, then earn it
A caller you did not change starts failing under the sanitizers after a class it uses was modernised — a pointer it held across an Add now dangles Chapter 45: source that still compiles is not behaviour that still holds; the address promise was part of the contract, and the container has to keep it

When more than one row fits, and you have no stack yet. It crashes at shutdown or unload is the common case: it matches the first row, the still-live-at-shutdown row and the callback row equally well, and the ticket that brought it rarely says which. Two questions settle the order, and both are answerable from your own source without reproducing anything. Does a global or function-local static own something on the failing path? If so start at Chapter 32 — your source names the statics, but not the order they are destroyed in, which is that chapter's whole subject. Does anything the host owns still hold a pointer to you — a registered callback, an observer, a refcount? Then Chapter 29 for the threaded case, Chapter 35 for the refcounted one — and the reverse question, do you hold an owner to something a framework's parent already owns?, is Chapter 44. If more than one is true, rule out the static first: it is the cheaper of the two, because it needs no repro to investigate.

The Gotchas, by symptom

Each Finding in Chapter 25 opens with what you see; this is that column on its own.

What you see Finding
A move that costs what a copy costs, and a moved-from object still holding its data — the Tracer's move operations written as name = "moved from " + t.name; Finding 1
A member assigned in the constructor body — all four of the Tracer's copy/move operations set name after the brace — and, the day the member is const or a reference, a constructor that does not compile Finding 2
noexcept on a move that allocates — so a std::bad_alloc inside it becomes std::terminate Finding 3
An assignment operator whose body is the constructor's — safe by luck in the Tracer, a leak the day the member is a raw pointer Finding 4
Code that reads a moved-from object expecting something — the question "what state is a in?" after Tracer c = std::move(a); Finding 5
Copy assignment that deletes the old block, then allocates the new one — correct in every test where allocation succeeds, a double free on the day it throws Finding 6
Fresh elements that read 0 on one machine and -842150451 on another — the Buffer constructor's data_(new int[size]) Finding 7
buf.At(2) = 7 does not compile — int At(size_t) const returned a copy, making the Buffer write-only through its own API Finding 8
A destructor doing more than freeing — if (data_) delete[] data_; data_ = nullptr; size_ = 0; Finding 9
A sabotage run that should have failed came back clean — removing the Buffer's self-move guard produced "no issues," which was itself the bug Finding 10
Container or call behaviour you cannot explain — which copy, which move, and when Finding 11