Coverage suppression merged into GCC

Coverage suppression merged into GCC

August 16, 2026

A few days ago I pushed support for coverage suppression in GCC. Sometimes we write very defensive guards, especially in debug builds (like asserts), that are intended to never trigger because they signal a logic bug elsewhere. It’s hard to argue that defensive code and asserts isn’t excellent, but they paradoxically introduce a problem for coverage since we now introduce decisions and code paths that will never be exercised. The new #pragma GCC suppress_coverage and __attribute__((suppress_coverage)) address this problem. GCC could already ignore files for coverage (with -fprofile-filter-files and -fprofile-exclude-files), but this is more granular.

The problem is easily demonstrated with a trivial example. n/m where m == 0 is undefined behaviour and inputs should be sanitized. The assert is there to find the cases when it isn’t.

double ratiof(unsigned int n, unsigned int m) {
    assert (m != 0);
    return (double)n / m;
}

The assert is really a branch, it expands to something of the effect of if (cond) abort(). Since the abort should never be reached we cannot achieve full coverage.

Now, what we could do is to simply ignore these false positives when we analyze the coverage report. The problem is that false positives poison the report and dull our sensitivity to problems, and we don’t detect new or surprising coverage. This is similar to why we want clean compiles, because under a deluge of warnings the real problems don’t stand out.

Here’s a slightly more sophisticated example. The comparison function given to qsort has these requirements:

comp is a comparison function which returns a negative integer value if the first argument is less than the second, a positive integer value if the first argument is greater than the second and zero if the arguments are equivalent.

These properties should be true for all calls to comp for all elements in the array. We want to verify this in our testsuite and can afford the (debug build) performance hit.

void qsort(void *ptr, size_t count, int (*comp)(const void*, const void*)) {
    // ...
    while (1) {
        void* x = ptr[bot];
        void* y = ptr[top];

#if defined(DEBUG)
        int lt = comp(x, y);
        int gt = comp(y, x);
        if (lt <  0) assert (gt > 0);
        if (lt == 0) assert (gt == 0);
        if (lt >  0) assert (gt < 0);
#endif
    }
    // ...
}

This would tank the coverage totals, while at the same providing stronger confidence in the provided comp functions and something we want to keep. We can fix the coverage problem with the suppress_coverage pragma:

void qsort(void *ptr, size_t count, int (*comp)(const void*, const void*)) {
    // ...
    while (1) {
        void* x = ptr[bot];
        void* y = ptr[top];

#if defined(DEBUG)
#pragma GCC suppress_coverage begin
        int lt = comp(x, y);
        int gt = comp(y, x);
        if (lt <  0) assert (gt > 0);
        if (lt == 0) assert (gt == 0);
        if (lt >  0) assert (gt < 0);
#pragma GCC suppress_coverage end
#endif
    }
    // ...
}

That’s it, really, and quite intuitive. The code in the suppress_coverage begin/end blocks won’t contribute to total coverage, and the (sub)paths that thread through the suppress_coverage block won’t be counted towards prime path coverage.

We can also suppress whole functions using the new __attribute__((suppress_coverage)) (or [[gnu::suppress_coverage]]) attribute. This is ideal for pure pre/post condition checking functions, but since it disables all coverage for the function it should probably be use sparingly to not suppress the code we do want to cover.

__attribute__((suppress_coverage))
double ratiof(unsigned int n, unsigned int m) {
    assert (m != 0);      // won't count for coverage
    return (double)n / m; // this won't either
}

This feature will be released with GCC 17 (spring 2027 probably), but can be backported to earlier releases. This feature was commissioned; Patch can support you in backporting coverage suppression or adding new features.