BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bslim_fuzzutil.h
Go to the documentation of this file.
1/// @file bslim_fuzzutil.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bslim_fuzzutil.h -*-C++-*-
8#ifndef INCLUDED_BSLIM_FUZZUTIL
9#define INCLUDED_BSLIM_FUZZUTIL
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bslim_fuzzutil bslim_fuzzutil
15/// @brief Provide fuzz test utilities for basic types.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bslim
19/// @{
20/// @addtogroup bslim_fuzzutil
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bslim_fuzzutil-purpose"> Purpose</a>
25/// * <a href="#bslim_fuzzutil-classes"> Classes </a>
26/// * <a href="#bslim_fuzzutil-description"> Description </a>
27/// * <a href="#bslim_fuzzutil-usage"> Usage </a>
28/// * <a href="#bslim_fuzzutil-example-1-consuming-integers-in-a-range-to-pass-to-an-interface"> Example 1: Consuming Integers in a Range to Pass to an Interface </a>
29///
30/// # Purpose {#bslim_fuzzutil-purpose}
31/// Provide fuzz test utilities for basic types.
32///
33/// # Classes {#bslim_fuzzutil-classes}
34///
35/// - bslim::FuzzUtil: functions to create basic types from fuzz data
36///
37/// @see bslim_fuzzdataview
38///
39/// # Description {#bslim_fuzzutil-description}
40/// This component provides a namespace, `bslim::FuzzUtil`,
41/// containing functions that create fundamental and standard library types from
42/// fuzz data provided by a fuzz harness (e.g., `libFuzzer`).
43///
44/// See {http://bburl/BDEFuzzTesting} for details on how to build and run with
45/// fuzz testing enabled.
46///
47/// ## Usage {#bslim_fuzzutil-usage}
48///
49///
50/// This section illustrates intended use of this component.
51///
52/// ### Example 1: Consuming Integers in a Range to Pass to an Interface {#bslim_fuzzutil-example-1-consuming-integers-in-a-range-to-pass-to-an-interface}
53///
54///
55/// Suppose we wish to fuzz test a function with preconditions.
56///
57/// First, we define the `TradingInterfaceUnderTest` `struct`:
58/// @code
59/// struct TradingInterfaceUnderTest {
60/// // This utility class provides sample functionality to demonstrate how
61/// // fuzz data might be used.
62///
63/// // CLASS METHODS
64/// static int numEarningsAnnouncements(int year, int month)
65/// // Return a value containing the number of earnings announcements
66/// // in the specified 'year' and 'month'. The behavior is undefined
67/// // unless '1950 < year < 2030' and 'month' is in '[1 .. 12]'. Note
68/// // that the values here are arbitrary, and in the real-world this
69/// // data would be obtained from a database or an API.
70/// {
71/// BSLS_ASSERT(1950 < year && year < 2030);
72/// BSLS_ASSERT( 1 <= month && month <= 12);
73///
74/// if (2020 < year && 6 < month) {
75/// return 11; // RETURN
76/// }
77/// return 6;
78/// }
79/// };
80/// @endcode
81/// Then, we need a block of raw bytes. This would normally come from a fuzz
82/// harness (e.g., the `LLVMFuzzerTestOneInput` entry point function from
83/// `libFuzzer`). Since `libFuzzer` is not available here, we initialize a
84/// `myFuzzData` array that we will use instead.
85/// @code
86/// const bsl::uint8_t myFuzzData[] = {0x43, 0x19, 0x0D, 0x44, 0x37, 0x0D,
87/// 0x38, 0x5E, 0x9B, 0xAA, 0xF3, 0xDA};
88/// @endcode
89/// Next, we create a `FuzzDataView` to wrap the raw bytes.
90/// @code
91/// bslim::FuzzDataView fdv(myFuzzData, sizeof myFuzzData);
92/// @endcode
93/// Now, we pass this `FuzzDataView` to `FuzzUtil` to generate values within the
94/// permissible range of the function under test:
95/// @code
96/// int month = bslim::FuzzUtil::consumeNumberInRange<int>(&fdv, 1, 12);
97/// int year = bslim::FuzzUtil::consumeNumberInRange<int>(&fdv, 1951, 2029);
98/// assert( 1 <= month && month <= 12);
99/// assert(1951 <= year && year <= 2029);
100/// @endcode
101/// Finally, we can use these `int` values to pass to a function that returns
102/// the number of earnings announcements scheduled in a given month.
103/// @code
104/// int numEarnings =
105/// TradingInterfaceUnderTest::numEarningsAnnouncements(year, month);
106/// (void) numEarnings;
107/// @endcode
108/// @}
109/** @} */
110/** @} */
111
112/** @addtogroup bsl
113 * @{
114 */
115/** @addtogroup bslim
116 * @{
117 */
118/** @addtogroup bslim_fuzzutil
119 * @{
120 */
121
122#include <bslscm_version.h>
123
124#include <bslim_fuzzdataview.h>
125
126#include <bslmf_assert.h>
127
128#include <bsls_assert.h>
129#include <bsls_libraryfeatures.h>
130#include <bsls_types.h> // 'bsls::Types::Uint64'
131
132#include <bsl_cmath.h> // 'bsl::isfinite'
133#include <bsl_cstdint.h> // 'bsl::uint8_t'
134#include <bsl_limits.h> // 'bsl::numeric_limits'
135#include <bsl_string.h>
136#include <bsl_type_traits.h> // 'bsl::is_same'
137#include <bsl_vector.h>
138
139#include <string>
140#include <vector>
141
142
143namespace bslim {
144
145 // ===============
146 // struct FuzzUtil
147 // ===============
148
149/// This utility `struct` provides a namespace for a suite of functions
150/// operating on objects of type `FuzzDataView`and providing the consumption
151/// of fuzz data bytes into fundamental and standard library types.
152struct FuzzUtil {
153
154 // CLASS METHODS
155
156 /// Return a `bool` value based upon consuming a single byte from the
157 /// specified `fuzzDataView`. If `fuzzDataView->length()` is 0, return
158 /// `false`.
159 static bool consumeBool(FuzzDataView *fuzzDataView);
160
161 template <class TYPE>
162 static typename bsl::enable_if<bsl::is_integral<TYPE>::value, TYPE>::type
163 consumeNumber(FuzzDataView *fuzzDataView);
164
165 /// Return a value of (template parameter) `TYPE` in the range
166 /// [min .. max] -- where `min` and `max` are the minimum and maximum
167 /// values representable by the `TYPE` -- based on at most the next
168 /// `sizeof(TYPE) + 1` bytes from the specified `fuzzDataView`, and
169 /// update `fuzzDataView` to reflect the bytes consumed. If
170 /// `0 == fuzzDataView->length()`, return the minimum value of `TYPE`.
171 /// This function does not participate in overload resolution unless
172 /// either `bsl::is_integral<TYPE>::value` or
173 /// `bsl::is_floating_point<TYPE>::value` is `true`. The behavior is
174 /// undefined if `bsl::is_same<TYPE, bool>::value` or
175 /// `bsl::is_same<TYPE, long double>` is `true`.
176 template <class TYPE>
177 static typename
180
181 /// Return a value of (template parameter) `TYPE` in the specified range
182 /// [min .. max] based on at most the next `sizeof(TYPE) + 1` bytes from
183 /// the specified `fuzzDataView`, and update `fuzzDataView` to reflect
184 /// the bytes consumed. If `0 == fuzzDataView->length()`, return the
185 /// specified `min`. This function does not participate in overload
186 /// resolution unless either `bsl::is_integral<TYPE>::value` or
187 /// `bsl::is_floating_point<TYPE>::value` is `true`. The behavior is
188 /// undefined if `min > max`, `min` or `max` is not finite, or either
189 /// `bsl::is_same<TYPE, bool>::value` or
190 /// `bsl::is_same<TYPE, long double>` is `true`.
191 template <class TYPE>
192 static typename
195 TYPE min,
196 TYPE max);
197 template <class TYPE>
198 static typename
200 consumeNumberInRange(FuzzDataView *fuzzDataView, TYPE min, TYPE max);
201
203 FuzzDataView *fuzzDataView,
204 bsl::size_t maxLength);
205 static void consumeRandomLengthChars(std::vector<char> *output,
206 FuzzDataView *fuzzDataView,
207 bsl::size_t maxLength);
208#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
209 static void consumeRandomLengthChars(std::pmr::vector<char> *output,
210 FuzzDataView *fuzzDataView,
211 bsl::size_t maxLength);
212#endif
213 // Load into the specified 'output' a sequence of characters of length from
214 // 0 to the specified 'maxLength'. If the specified 'fuzzDataView' has
215 // fewer bytes than 'maxLength', load at most 'fuzzDataView->length()'
216 // bytes into 'output'. If the buffer in 'fuzzDataView' contains two
217 // successive backslash characters, then in 'output' they will be converted
218 // to a single backslash ('\\') character; if a single backslash character
219 // is encountered, the consumption of bytes is terminated. Note that
220 // because double backslashes are mapped to single backslashes, more than
221 // 'maxLength' bytes may be consumed from the buffer to produce the
222 // 'output'. Also note that the purpose of this function is to enable the
223 // creation of a non-zero-terminated @ref string_view , which is not possible
224 // with the 'string' counterpart.
225
227 FuzzDataView *fuzzDataView,
228 bsl::size_t maxLength);
229 static void consumeRandomLengthString(std::string *output,
230 FuzzDataView *fuzzDataView,
231 bsl::size_t maxLength);
232#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR_STRING
233 static void consumeRandomLengthString(std::pmr::string *output,
234 FuzzDataView *fuzzDataView,
235 bsl::size_t maxLength);
236#endif
237 // Load into the specified 'output' a string of length from 0 to the
238 // specified 'maxLength'. If the specified 'fuzzDataView' has fewer
239 // bytes than 'maxLength', load at most 'fuzzDataView->length()' bytes
240 // into 'output'. If the buffer in 'fuzzDataView' contains two
241 // successive backslash characters, then in 'output' they will be
242 // converted to a single backslash ('\\') character; if a single
243 // backslash character is encountered, the consumption of bytes is
244 // terminated. Note that because double backslashes are mapped to
245 // single backslashes, more than 'maxLength' bytes may be consumed
246 // from the buffer to produce the 'output'.
247};
248
249// ============================================================================
250// INLINE DEFINITIONS
251// ============================================================================
252
253 // ---------------
254 // struct FuzzUtil
255 // ---------------
256
257// CLASS METHODS
258inline
260{
261 return 1 & consumeNumber<bsl::uint8_t>(fuzzDataView);
262}
263
264template <class TYPE>
267{
268 return consumeNumberInRange(fuzzDataView,
269 bsl::numeric_limits<TYPE>::min(),
270 bsl::numeric_limits<TYPE>::max());
271}
272
273template <class TYPE>
274typename
277{
278 return consumeNumberInRange(fuzzDataView,
279 -bsl::numeric_limits<TYPE>::max(),
280 bsl::numeric_limits<TYPE>::max());
281}
282
283template <class TYPE>
285FuzzUtil::consumeNumberInRange(FuzzDataView *fuzzDataView, TYPE min, TYPE max)
286{
289 BSLMF_ASSERT(sizeof(TYPE) <= sizeof(bsls::Types::Uint64));
290 BSLS_ASSERT(min <= max);
291
292 bsls::Types::Uint64 range = static_cast<bsls::Types::Uint64>(max) - min;
293
294 int numBytes = 0;
295
296 for (bsls::Types::Uint64 rangeCpy = range; 0 != rangeCpy;
297 rangeCpy >>= 8, ++numBytes) {
298 }
299
300 bsls::Types::Uint64 addend = 0;
301
302 FuzzDataView prefix = fuzzDataView->removePrefix(numBytes);
303
304 for (const bsl::uint8_t *it = prefix.begin(); it != prefix.end(); it++) {
305 addend = (addend << 8) | *it;
306 }
307
308 if (bsl::numeric_limits<bsls::Types::Uint64>::max() != range) {
309 addend %= (range + 1);
310 }
311
312 return static_cast<TYPE>(min + addend);
313}
314
315template <class TYPE>
317FuzzUtil::consumeNumberInRange(FuzzDataView *fuzzDataView, TYPE min, TYPE max)
318{
320 BSLMF_ASSERT(bsl::numeric_limits<TYPE>::has_infinity);
321
322 BSLS_ASSERT(min <= max);
323
324 BSLS_ASSERT(min == min && max == max);
325 BSLS_ASSERT(bsl::numeric_limits<TYPE>::infinity() != max &&
326 -bsl::numeric_limits<TYPE>::infinity() != min);
327
328 TYPE addend = min;
329 TYPE range = 0;
330 const TYPE k_HALF = 0.5;
331
332 if (max > min + bsl::numeric_limits<TYPE>::max()) {
333 range = max * k_HALF - min * k_HALF;
334 if (consumeBool(fuzzDataView)) {
335 addend = min + range;
336 }
337 }
338 else {
339 range = max - min;
340 }
341
342 typedef typename bsl::conditional<(sizeof(TYPE) <= sizeof(bsl::uint32_t)),
343 bsl::uint32_t,
344 bsls::Types::Uint64>::type IntegralType;
345
346 TYPE factor =
347 static_cast<TYPE>(consumeNumber<IntegralType>(fuzzDataView)) /
348 static_cast<TYPE>(
349 bsl::numeric_limits<IntegralType>::max()); // between 0-1
350
351 return addend + range * factor;
352}
353
354} // close package namespace
355
356
357#endif
358
359// ----------------------------------------------------------------------------
360// Copyright 2021 Bloomberg Finance L.P.
361//
362// Licensed under the Apache License, Version 2.0 (the "License");
363// you may not use this file except in compliance with the License.
364// You may obtain a copy of the License at
365//
366// http://www.apache.org/licenses/LICENSE-2.0
367//
368// Unless required by applicable law or agreed to in writing, software
369// distributed under the License is distributed on an "AS IS" BASIS,
370// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
371// See the License for the specific language governing permissions and
372// limitations under the License.
373// ----------------------------- END-OF-FILE ----------------------------------
374
375/** @} */
376/** @} */
377/** @} */
Definition bslstl_string.h:1281
Definition bslstl_vector.h:1025
Definition bslim_fuzzdataview.h:130
const bsl::uint8_t * end() const
Return a const pointer to the end of the buffer.
Definition bslim_fuzzdataview.h:234
const bsl::uint8_t * begin() const
Return a const pointer to the beginning of the buffer.
Definition bslim_fuzzdataview.h:228
FuzzDataView removePrefix(bsl::size_t numBytes)
Definition bslim_fuzzdataview.h:205
#define BSLMF_ASSERT(expr)
Definition bslmf_assert.h:229
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1804
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition bslim_formatguard.h:120
Definition bslmf_conditional.h:120
Definition bslmf_enableif.h:525
Definition bslmf_isintegral.h:130
Definition bslmf_issame.h:146
Definition bslim_fuzzutil.h:152
static void consumeRandomLengthChars(bsl::vector< char > *output, FuzzDataView *fuzzDataView, bsl::size_t maxLength)
static void consumeRandomLengthString(std::string *output, FuzzDataView *fuzzDataView, bsl::size_t maxLength)
static bool consumeBool(FuzzDataView *fuzzDataView)
Definition bslim_fuzzutil.h:259
static bsl::enable_if< bsl::is_integral< TYPE >::value, TYPE >::type consumeNumber(FuzzDataView *fuzzDataView)
Definition bslim_fuzzutil.h:266
static bsl::enable_if< bsl::is_integral< TYPE >::value, TYPE >::type consumeNumberInRange(FuzzDataView *fuzzDataView, TYPE min, TYPE max)
Definition bslim_fuzzutil.h:285
static void consumeRandomLengthChars(std::vector< char > *output, FuzzDataView *fuzzDataView, bsl::size_t maxLength)
static void consumeRandomLengthString(bsl::string *output, FuzzDataView *fuzzDataView, bsl::size_t maxLength)
static bsl::enable_if< bsl::is_floating_point< TYPE >::value, TYPE >::type consumeNumberInRange(FuzzDataView *fuzzDataView, TYPE min, TYPE max)
static bsl::enable_if< bsl::is_floating_point< TYPE >::value, TYPE >::type consumeNumber(FuzzDataView *fuzzDataView)
unsigned long long Uint64
Definition bsls_types.h:137