BDE 4.14.0 Production release
|
Macros | |
#define | BSLS_FUZZTEST_EVALUATE_IMP(X) |
#define | BSLS_FUZZTEST_EVALUATE_RAW_IMP(X) |
#define | BSLS_FUZZTEST_EVALUATE(X) |
#define | BSLS_FUZZTEST_EVALUATE_RAW(X) |
Provide macros for use in fuzz testing narrow-contract functions.
This component provides two macros, BSLS_FUZZTEST_EVALUATE
and BSLS_FUZZTEST_EVALUATE_RAW
, that can be used in fuzz testing narrow contract functions. They are intended to be used in conjunction with bsls::FuzzTestHandlerGuard
as well as BSLS_PRECONDITIONS_BEGIN
and BSLS_PRECONDITIONS_END
.
When fuzzing narrow contract functions, if we do not wish to "massage" the data we pass to the function (as this may be error-prone and might introduce bias into the tested input) we must address the issue that we will often invoke the function out of contract, and this will cause the function to assert, and the test to end prematurely. The macros defined in this component solve this issue by detecting the location of precondition violations. Functions with narrow contracts that are to be tested must be decorated with the BSLS_PRECONDITIONS_BEGIN
and BSLS_PRECONDITIONS_END
macros. These macros must be placed just before and after the function preconditions are checked.
All these macros are intended to be used in fuzzing builds in which BDE_ACTIVATE_FUZZ_TESTING
is defined. For our purposes, those preconditions that fail in the function under test (i.e., the one invoked by BSLS_FUZZTEST_EVALUATE
) are treated differently from all other precondition failures. We refer to these preconditions as "top-level" preconditions. If a top-level precondition fails – and the assertion is not from another component – the execution will continue: we do not wish to stop the fuzz test if we simply invoked the narrow contract function under test out of contract. We wish to detect only subsequent assertions (i.e., not in the top-level), or assertions from other components.
The BSLS_FUZZTEST_EVALUATE_RAW
macro does not check if the assertion originates from another component, though, like the non-RAW
version, it ignores only top-level assertions. This behavior is desirable in cases in which a function delegates its implementation and associated precondition checks to a different component. In such cases, a precondition failure ought not cause the fuzz test to end.
This section illustrates intended use of this component.
The macros in this component rely upon the presence of related macros from bsls_preconditions . The fuzzing macros are typically used in a fuzzing build, in which case the entry point is LLVMFuzzerTestOneInput
.
In this example, we illustrate the intended usage of two macros: BSLS_FUZZTEST_EVALUATE
and BSLS_FUZZTEST_EVALUATE_RAW
.
First, in order to illustrate the use of BSLS_FUZZTEST_EVALUATE
, we define two functions that implement the sqrt
function, both decorated with the precondition BEGIN
and END
macros. mySqrt
forwards its argument to newtonsSqrt
, which has a slightly more restrictive precondition: mySqrt
accepts 0, while newtonsSqrt
does not.
Then, for the illustration of BSLS_FUZZTEST_EVALUATE_RAW
, we define a class, Timer
, containing a start
function that uses in its implementation a narrow contract function, setInterval
, from another component, bsls::TimeInterval
. This function, setInterval
, has precondition checks that are surrounded by BEGIN
and END
.
Next, implement LLVMFuzzerTestOneInput
. We first select the test case number based on the supplied fuzz data.
Then, we implement the test case to illustrate the use of BSLS_FUZZTEST_EVALUATE
.
Next, we set up the handler guard that installs the precondition handlers.
Now, we invoke the function under test (i.e., mySqrt
) with the BSLS_FUZZTEST_EVALUATE
macro.
If the input
value obtained from the fuzz data is positive (e.g., 4.0), the mySqrt
implementation generates correct results without any errors. For negative inputs (e.g., -4.0), because the precondition violation occurs in the top level, execution of the test does not halt. If 0 is passed as the input, mySqrt
forwards it to newtonsSqrt
where a second-level assertion occurs and execution halts, indicating a defect in the implementation of mySqrt
.
Next, we implement the test case to illustrate the use of BSLS_FUZZTEST_EVALUATE_RAW
.
Now, we set up the handler guard that installs the precondition handlers.
Finally, we invoke the function under test with the BSLS_FUZZTEST_EVALUATE_RAW
macro.
If the total number of seconds resulting from the sum of seconds
and nanoseconds
cannot be represented with a 64-bit signed integer, a top-level assertion failure from a different component will occur. Because we have invoked start
with the RAW
macro, a component name check will not be performed, and execution will continue.
Note that the use of bslim::FuzzUtil
and bslim::FuzzDataView
can simplify the consumption of fuzz data.
#define BSLS_FUZZTEST_EVALUATE | ( | X | ) |
#define BSLS_FUZZTEST_EVALUATE_IMP | ( | X | ) |
#define BSLS_FUZZTEST_EVALUATE_RAW | ( | X | ) |
#define BSLS_FUZZTEST_EVALUATE_RAW_IMP | ( | X | ) |