MemorySanitizer (MSan)
/ MSan -> EM-san /
In C, memory you get from malloc() or an uninitialized local variable holds whatever garbage was there before - it is not zeroed. Reading such a value before you have written anything meaningful into it is a bug: your program acts on leftover junk, and worse, the junk may happen to look reasonable on one run and disastrous on the next. MemorySanitizer is a tool dedicated to one job: catching the use of uninitialized memory - the moment a program's behavior depends on a value that was never set.
Concretely, MSan is a clang sanitizer enabled with -fsanitize=memory (and -g). The compiler shadows every value with bits tracking whether it is initialized, and propagates that 'tainted' status through copies and arithmetic. Crucially, MSan does not complain the instant you read uninitialized memory - it complains when an uninitialized value actually influences observable behavior, such as branching on it, using it as an array index, or passing it to a system call. At that point it prints a report with the stack trace of the use and, helpfully, where the uninitialized memory originated. This is the gap memcheck and ASan leave: ASan by default does not flag uninitialized reads, so MSan fills it.
Why it matters: uninitialized-read bugs are insidious precisely because they sometimes 'work' - the leftover bytes happen to be zero, or happen to be in range - so the program passes tests and fails in the field. MSan turns that lottery into a definite, located error. Honest caveats and a real practical cost: MSan is clang-only, and it requires that ALL code be instrumented, including the C library and every dependency - any uninstrumented library that writes to your memory will produce false positives, so in practice you need an instrumented libc++/standard library. That makes MSan more demanding to set up than ASan or UBSan, which is why teams often reach for it specifically when chasing an uninitialized-data bug rather than running it always.
$ clang -g -fsanitize=memory uninit.c -o a on code that does int x; if (x > 0) ... (reading x before assigning) prints 'use-of-uninitialized-value' with the line of the branch and where x was declared - whereas a plain build might run differently each time depending on stack garbage.
MSan flags a branch that depends on an uninitialized variable, with its origin.
MSan reports the use of an uninitialized value, not its mere existence, and demands that all code (including libc) be instrumented or it raises false positives - so it is clang-only and harder to deploy than ASan/UBSan. Remember malloc() does not zero memory (calloc() does), which is why these bugs exist.