Comprehensive Fuzzing Is a Coverage Design Problem

CombiSan offers a concrete answer to the question behind this series: comprehensive fuzzing is not achieved by collecting a longer list of sanitizer names. It depends on whether the detectors can observe the same executions, preserve the state each one needs, and let the fuzzer retain more than the first report. This final synthesis connects those conditions to the study's evidence and turns them into a conditional way to judge a unified run, separate runs, or a layered combination.

The unit of coverage is the execution

The most important connection is between detector semantics and campaign behavior. ASan, MSan, and UBSan are not three interchangeable opinions about the same event. ASan watches whether an access is addressable, using memory boundaries such as redzones and quarantine. MSan follows whether initialization state reaches a meaningful use, which requires information to travel through computations and across important dependencies. UBSan checks selected operations for undefined behavior and can report, continue, exit, or trap according to the check and runtime policy.

Those differences matter only when the relevant detector is present at the moment the behavior occurs. A campaign that runs ASan and UBSan on one input stream and MSan on another may eventually produce three sets of reports, but it has not given every generated input the same observation. The fuzzer's mutations and feedback evolve separately, and an early report can stop an input before another class of problem is reached. The coverage unit is therefore not the build configuration alone. It is the execution together with the state, detectors, and control policy that governed it.

This is why CombiSan's contribution is architectural rather than cosmetic. Its shared shadow state gives addressability and initialization a common representation, while its access-level instrumentation is designed to coexist with UBSan's operation checks. Its deferred error handling changes another boundary: a violation is first recorded, then the fuzzer decides what to do after the test case has yielded its available observations. The design does not make the categories identical. It makes their observations more likely to coexist on the same input.

That distinction also explains what “comprehensive” can and cannot mean here. Within the paper's scope, CombiSan combines addressability issues, uses of uninitialized memory, and other undefined behavior covered by the selected ASan, MSan, and UBSan capabilities. It does not cover every memory defect, every race, type confusion, logic error, kernel-specific condition, or production security concern. The word describes the union of a stated set of detector classes under a stated fuzzing design; it is not a synonym for complete software assurance.

A useful way to reason about the result is to separate four questions that are often collapsed into one:

  1. Can the detector recognize the defect? This is a question about instrumentation and analysis accuracy.
  2. Did the fuzzer generate the triggering input? This is a question about mutations, coverage feedback, and campaign entropy.
  3. Did the input reach the relevant operation before another report ended execution? This is a question about termination and aggregation policy.
  4. Could the runtime see the code and state involved? This is a question about dependency instrumentation, library boundaries, replay, and the target environment.

CombiSan addresses all four, but in different ways. The shared memory state and UBSan-compatible instrumentation address the first and fourth at the design level. Deferred analysis addresses the third. Running one coordinated detector over the same input population improves the conditions for the second, without making input generation deterministic or guaranteed. Keeping those mechanisms separate prevents a speed claim from being mistaken for a proof of accuracy, or an accuracy result from being mistaken for proof of broader campaign coverage.

The same model clarifies why separate runs are not automatically wrong. If a target cannot satisfy a detector's dependency requirements, if an environment lacks a suitable confirmation path, or if a particular detector must be isolated to understand its reports, a separate run may be the honest option.