BullseyeCoverage
BullseyeCoverage is a code coverage analyzer for the C and C++ languages. With BullseyeCoverage, you can:
The steps involved in using BullseyeCoverage are:
BullseyeCoverage cannot measure coverage of assembly code.
When coverage build is enabled, BullseyeCoverage intercepts compiler invocations to perform instrumentation.
Information about the code is written to the coverage file,
named test.cov
by default.
The instrumented code is compiled using your compiler.
At run-time,
the coverage file is updated with coverage measurements.
The COVFILE
environment variable names the coverage file.
You can view the coverage file using the
Coverage Browser
or the
command line report programs.
BullseyeCoverage measures condition/decision coverage and function coverage. The following specific events are monitored.
if
,
if
-else
, while
, do
-while
,
and for
statements.
A decision is an expression that uses the logical operators &&
or ||
outside such a controlling expression.
The first operand of the ?:
operator is a decision if the ?:
occurs outside a controlling expression.
In the example code below, the decisions are marked by yellow boxes.
if (v1 == v2 && (v3 || v4)) v5 = v6 ? v7 : v8; if (v6 ? v7 : v8) v9 = (v10 || v11) ? v12 : v13; if ((v10 || v11) ? v12 : v13) v14 = v15 || v16;
&&
and ||
that does not contain logical operators.
The ?:
operator is also a logical operator.
The first operand of the ?:
operator is a condition
if it does not contain logical operators and the ?:
occurs in a decision.
In the example code below, the conditions are marked by blue boxes.
if (v1 == v2 && (v3 || v4)) v5 = v6 ? v7 : v8; if (v6 ? v7 : v8) v9 = (v10 || v11) ? v12 : v13; if ((v10 || v11) ? v12 : v13) v14 = v15 || v16;
case
and default
label was selected.
When the default
label is omitted,
the branch to the end of the switch
statement is indicated.
For example, BullseyeCoverage indicates whether control flowed to each of the pink boxed areas below.
switch (a) { case 1: case 2: statements break; } // Implicit default
__try
, __except
) is indicated similarly.
For example, BullseyeCoverage indicates whether control flowed to the pink boxed area below.
try { statements } catch (exception-declaration) { statements } catch (...) { statements }
void function()
{
statements
}
[] { statements }
for
statement body was entered.
for (for-range-declaration: expression) statement
By default, BullseyeCoverage does not measure coverage of code produced by macro expansion.
BullseyeCoverage does not measure coverage of variable initializers at file scope.
BullseyeCoverage does not measure coverage of static
variable initializers in C.
These initializers are evaluated at compile-time.
BullseyeCoverage does not measure coverage of functions declared consteval
or constexpr
.
These functions might be evaluated at compile-time.
BullseyeCoverage measures coverage in template functions the same way as non-template functions. Coverage is measured by instrumenting the source code. Coverage in all template instantiations is combined and reported together.
These are general guidelines for usage of C++ features and tools that can have an impact on coverage measurement.
&&
and ||
.
Defining these operators with operand type or return type other than bool
conflicts with condition/decision coverage at a basic level.
In addition to the conflict with condition/decision coverage,
overloading operators &&
and ||
is not recommended due to these semantic differences:
Use the alternative tokens 'and
' and 'or
' rather than the token spellings '&&
' and '||
'.
The token &&
is used for multiple purposes,
which can be difficult to distinguish.
The token &&
serves as both the logical-and operator as well as the rvalue reference qualifier.
With GCC and Clang, &&
is also a unary operator taking the address of a label.
BullseyeCoverage recognizes 'and
' as the logical-and operator unambiguously.
To enable the alternative tokens with Microsoft C++,
use compiler option
/permissive-
or use C++20 or later,
for example with
/std:c++20
.
Declare constant-initialized variables with constinit
or constexpr
rather than const
wherever possible.
This helps BullseyeCoverage identify expressions that cannot be modified with run-time instrumentation.
constexpr
.
Because constexpr
functions might evaluate at compile-time,
BullseyeCoverage cannot add run-time instrumentation.
When a constexpr
function evaluates at run-time,
code coverage measurement goes unreported.
To address safety-critical code coverage requirements,
remove the constexpr
keyword from each function.
If any invocation of such a function occurs in a constant expression,
make a copy of the function with a different name declared consteval
for those cases.
/Zc:preprocessor
to enable the conforming preprocessor.
The Microsoft traditional preprocessor is buggy and idiosyncratic.
Although we make considerable effort to mimic this incorrect behavior,
it is not always possible and in rare instances the differences lead to a failed build.
The Microsoft conforming preprocessor behaves properly,
eliminating the possibility of a difference in behavior when using BullseyeCoverage.
/permissive-
or use C++20 or later,
for example with
/std:c++20
.
If this is not feasible,
enable covc option --strict
.
These options ensure that latent errors in uninstantiated templates and other standards violations
result in straightforward error messages that are easy to understand and fix.
Without these options,
errors in uninstantiated templates lead to confusing symptoms.
/external:I
rather than /I
to specify include directories containing code written and tested outside your project.
BullseyeCoverage automatically excludes code included via /external:I
.
-isystem
rather than -I
to specify include directories containing code written and tested outside your project.
BullseyeCoverage automatically excludes code included via -isystem
.
Instrumenting with BullseyeCoverage typically increases execution time to 1.2x, code size to 1.4x and compile time to 1.7x with most Microsoft C++ projects, 3-8x with other compilers. Your results may vary. Compiler optimization settings greatly improve performance of instrumented code.
BullseyeCoverage may modify compiler options and directives affecting performance. These changes may include, but are not limited to, the following.
for
directive (#pragma omp parallel for) is disabled
Updated: 6 Sep 2024
Copyright © Bullseye Testing Technology. All Rights Reserved.