Mercurial > hg
annotate contrib/fuzz/FuzzedDataProvider.h @ 45095:8e04607023e5
procutil: ensure that procutil.std{out,err}.write() writes all bytes
Python 3 offers different kind of streams and it’s not guaranteed for all of
them that calling write() writes all bytes.
When Python is started in unbuffered mode, sys.std{out,err}.buffer are
instances of io.FileIO, whose write() can write less bytes for
platform-specific reasons (e.g. Linux has a 0x7ffff000 bytes maximum and could
write less if interrupted by a signal; when writing to Windows consoles, it’s
limited to 32767 bytes to avoid the "not enough space" error). This can lead to
silent loss of data, both when using sys.std{out,err}.buffer (which may in fact
not be a buffered stream) and when using the text streams sys.std{out,err}
(I’ve created a CPython bug report for that:
https://bugs.python.org/issue41221).
Python may fix the problem at some point. For now, we implement our own wrapper
for procutil.std{out,err} that calls the raw stream’s write() method until all
bytes have been written. We don’t use sys.std{out,err} for larger writes, so I
think it’s not worth the effort to patch them.
author | Manuel Jacob <me@manueljacob.de> |
---|---|
date | Fri, 10 Jul 2020 12:27:58 +0200 |
parents | 5a9e2ae9899b |
children |
rev | line source |
---|---|
43813
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
1 //===- FuzzedDataProvider.h - Utility header for fuzz targets ---*- C++ -* ===// |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
2 // |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
4 // See https://llvm.org/LICENSE.txt for license information. |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
6 // |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
7 //===----------------------------------------------------------------------===// |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
8 // A single header library providing an utility class to break up an array of |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
9 // bytes. Whenever run on the same input, provides the same output, as long as |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
10 // its methods are called in the same order, with the same arguments. |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
11 //===----------------------------------------------------------------------===// |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
12 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
13 #ifndef LLVM_FUZZER_FUZZED_DATA_PROVIDER_H_ |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
14 #define LLVM_FUZZER_FUZZED_DATA_PROVIDER_H_ |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
15 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
16 #include <algorithm> |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
17 #include <climits> |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
18 #include <cstddef> |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
19 #include <cstdint> |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
20 #include <cstring> |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
21 #include <initializer_list> |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
22 #include <string> |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
23 #include <type_traits> |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
24 #include <utility> |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
25 #include <vector> |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
26 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
27 // In addition to the comments below, the API is also briefly documented at |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
28 // https://github.com/google/fuzzing/blob/master/docs/split-inputs.md#fuzzed-data-provider |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
29 class FuzzedDataProvider |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
30 { |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
31 public: |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
32 // |data| is an array of length |size| that the FuzzedDataProvider wraps |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
33 // to provide more granular access. |data| must outlive the |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
34 // FuzzedDataProvider. |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
35 FuzzedDataProvider(const uint8_t *data, size_t size) |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
36 : data_ptr_(data), remaining_bytes_(size) |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
37 { |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
38 } |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
39 ~FuzzedDataProvider() = default; |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
40 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
41 // Returns a std::vector containing |num_bytes| of input data. If fewer |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
42 // than |num_bytes| of data remain, returns a shorter std::vector |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
43 // containing all of the data that's left. Can be used with any byte |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
44 // sized type, such as char, unsigned char, uint8_t, etc. |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
45 template <typename T> std::vector<T> ConsumeBytes(size_t num_bytes) |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
46 { |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
47 num_bytes = std::min(num_bytes, remaining_bytes_); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
48 return ConsumeBytes<T>(num_bytes, num_bytes); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
49 } |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
50 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
51 // Similar to |ConsumeBytes|, but also appends the terminator value at |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
52 // the end of the resulting vector. Useful, when a mutable |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
53 // null-terminated C-string is needed, for example. But that is a rare |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
54 // case. Better avoid it, if possible, and prefer using |ConsumeBytes| |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
55 // or |ConsumeBytesAsString| methods. |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
56 template <typename T> |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
57 std::vector<T> ConsumeBytesWithTerminator(size_t num_bytes, |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
58 T terminator = 0) |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
59 { |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
60 num_bytes = std::min(num_bytes, remaining_bytes_); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
61 std::vector<T> result = |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
62 ConsumeBytes<T>(num_bytes + 1, num_bytes); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
63 result.back() = terminator; |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
64 return result; |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
65 } |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
66 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
67 // Returns a std::string containing |num_bytes| of input data. Using |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
68 // this and |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
69 // |.c_str()| on the resulting string is the best way to get an |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
70 // immutable null-terminated C string. If fewer than |num_bytes| of data |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
71 // remain, returns a shorter std::string containing all of the data |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
72 // that's left. |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
73 std::string ConsumeBytesAsString(size_t num_bytes) |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
74 { |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
75 static_assert(sizeof(std::string::value_type) == |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
76 sizeof(uint8_t), |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
77 "ConsumeBytesAsString cannot convert the data to " |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
78 "a string."); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
79 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
80 num_bytes = std::min(num_bytes, remaining_bytes_); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
81 std::string result( |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
82 reinterpret_cast<const std::string::value_type *>( |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
83 data_ptr_), |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
84 num_bytes); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
85 Advance(num_bytes); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
86 return result; |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
87 } |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
88 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
89 // Returns a number in the range [min, max] by consuming bytes from the |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
90 // input data. The value might not be uniformly distributed in the given |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
91 // range. If there's no input data left, always returns |min|. |min| |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
92 // must be less than or equal to |max|. |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
93 template <typename T> T ConsumeIntegralInRange(T min, T max) |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
94 { |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
95 static_assert(std::is_integral<T>::value, |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
96 "An integral type is required."); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
97 static_assert(sizeof(T) <= sizeof(uint64_t), |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
98 "Unsupported integral type."); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
99 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
100 if (min > max) |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
101 abort(); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
102 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
103 // Use the biggest type possible to hold the range and the |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
104 // result. |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
105 uint64_t range = static_cast<uint64_t>(max) - min; |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
106 uint64_t result = 0; |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
107 size_t offset = 0; |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
108 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
109 while (offset < sizeof(T) * CHAR_BIT && (range >> offset) > 0 && |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
110 remaining_bytes_ != 0) { |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
111 // Pull bytes off the end of the seed data. |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
112 // Experimentally, this seems to allow the fuzzer to |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
113 // more easily explore the input space. This makes |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
114 // sense, since it works by modifying inputs that caused |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
115 // new code to run, and this data is often used to |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
116 // encode length of data read by |ConsumeBytes|. |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
117 // Separating out read lengths makes it easier modify |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
118 // the contents of the data that is actually read. |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
119 --remaining_bytes_; |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
120 result = |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
121 (result << CHAR_BIT) | data_ptr_[remaining_bytes_]; |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
122 offset += CHAR_BIT; |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
123 } |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
124 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
125 // Avoid division by 0, in case |range + 1| results in overflow. |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
126 if (range != std::numeric_limits<decltype(range)>::max()) |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
127 result = result % (range + 1); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
128 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
129 return static_cast<T>(min + result); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
130 } |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
131 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
132 // Returns a std::string of length from 0 to |max_length|. When it runs |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
133 // out of input data, returns what remains of the input. Designed to be |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
134 // more stable with respect to a fuzzer inserting characters than just |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
135 // picking a random length and then consuming that many bytes with |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
136 // |ConsumeBytes|. |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
137 std::string ConsumeRandomLengthString(size_t max_length) |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
138 { |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
139 // Reads bytes from the start of |data_ptr_|. Maps "\\" to "\", |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
140 // and maps "\" followed by anything else to the end of the |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
141 // string. As a result of this logic, a fuzzer can insert |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
142 // characters into the string, and the string will be lengthened |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
143 // to include those new characters, resulting in a more stable |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
144 // fuzzer than picking the length of a string independently from |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
145 // picking its contents. |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
146 std::string result; |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
147 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
148 // Reserve the anticipated capaticity to prevent several |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
149 // reallocations. |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
150 result.reserve(std::min(max_length, remaining_bytes_)); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
151 for (size_t i = 0; i < max_length && remaining_bytes_ != 0; |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
152 ++i) { |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
153 char next = ConvertUnsignedToSigned<char>(data_ptr_[0]); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
154 Advance(1); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
155 if (next == '\\' && remaining_bytes_ != 0) { |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
156 next = |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
157 ConvertUnsignedToSigned<char>(data_ptr_[0]); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
158 Advance(1); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
159 if (next != '\\') |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
160 break; |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
161 } |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
162 result += next; |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
163 } |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
164 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
165 result.shrink_to_fit(); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
166 return result; |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
167 } |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
168 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
169 // Returns a std::vector containing all remaining bytes of the input |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
170 // data. |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
171 template <typename T> std::vector<T> ConsumeRemainingBytes() |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
172 { |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
173 return ConsumeBytes<T>(remaining_bytes_); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
174 } |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
175 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
176 // Returns a std::string containing all remaining bytes of the input |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
177 // data. Prefer using |ConsumeRemainingBytes| unless you actually need a |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
178 // std::string object. |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
179 std::string ConsumeRemainingBytesAsString() |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
180 { |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
181 return ConsumeBytesAsString(remaining_bytes_); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
182 } |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
183 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
184 // Returns a number in the range [Type's min, Type's max]. The value |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
185 // might not be uniformly distributed in the given range. If there's no |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
186 // input data left, always returns |min|. |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
187 template <typename T> T ConsumeIntegral() |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
188 { |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
189 return ConsumeIntegralInRange(std::numeric_limits<T>::min(), |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
190 std::numeric_limits<T>::max()); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
191 } |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
192 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
193 // Reads one byte and returns a bool, or false when no data remains. |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
194 bool ConsumeBool() |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
195 { |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
196 return 1 & ConsumeIntegral<uint8_t>(); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
197 } |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
198 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
199 // Returns a copy of the value selected from the given fixed-size |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
200 // |array|. |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
201 template <typename T, size_t size> |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
202 T PickValueInArray(const T (&array)[size]) |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
203 { |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
204 static_assert(size > 0, "The array must be non empty."); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
205 return array[ConsumeIntegralInRange<size_t>(0, size - 1)]; |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
206 } |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
207 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
208 template <typename T> |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
209 T PickValueInArray(std::initializer_list<const T> list) |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
210 { |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
211 // TODO(Dor1s): switch to static_assert once C++14 is allowed. |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
212 if (!list.size()) |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
213 abort(); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
214 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
215 return *(list.begin() + |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
216 ConsumeIntegralInRange<size_t>(0, list.size() - 1)); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
217 } |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
218 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
219 // Returns an enum value. The enum must start at 0 and be contiguous. It |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
220 // must also contain |kMaxValue| aliased to its largest (inclusive) |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
221 // value. Such as: enum class Foo { SomeValue, OtherValue, kMaxValue = |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
222 // OtherValue }; |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
223 template <typename T> T ConsumeEnum() |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
224 { |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
225 static_assert(std::is_enum<T>::value, |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
226 "|T| must be an enum type."); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
227 return static_cast<T>(ConsumeIntegralInRange<uint32_t>( |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
228 0, static_cast<uint32_t>(T::kMaxValue))); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
229 } |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
230 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
231 // Returns a floating point number in the range [0.0, 1.0]. If there's |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
232 // no input data left, always returns 0. |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
233 template <typename T> T ConsumeProbability() |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
234 { |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
235 static_assert(std::is_floating_point<T>::value, |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
236 "A floating point type is required."); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
237 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
238 // Use different integral types for different floating point |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
239 // types in order to provide better density of the resulting |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
240 // values. |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
241 using IntegralType = |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
242 typename std::conditional<(sizeof(T) <= sizeof(uint32_t)), |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
243 uint32_t, uint64_t>::type; |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
244 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
245 T result = static_cast<T>(ConsumeIntegral<IntegralType>()); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
246 result /= |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
247 static_cast<T>(std::numeric_limits<IntegralType>::max()); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
248 return result; |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
249 } |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
250 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
251 // Returns a floating point value in the range [Type's lowest, Type's |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
252 // max] by consuming bytes from the input data. If there's no input data |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
253 // left, always returns approximately 0. |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
254 template <typename T> T ConsumeFloatingPoint() |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
255 { |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
256 return ConsumeFloatingPointInRange<T>( |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
257 std::numeric_limits<T>::lowest(), |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
258 std::numeric_limits<T>::max()); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
259 } |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
260 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
261 // Returns a floating point value in the given range by consuming bytes |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
262 // from the input data. If there's no input data left, returns |min|. |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
263 // Note that |min| must be less than or equal to |max|. |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
264 template <typename T> T ConsumeFloatingPointInRange(T min, T max) |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
265 { |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
266 if (min > max) |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
267 abort(); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
268 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
269 T range = .0; |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
270 T result = min; |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
271 constexpr T zero(.0); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
272 if (max > zero && min < zero && |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
273 max > min + std::numeric_limits<T>::max()) { |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
274 // The diff |max - min| would overflow the given |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
275 // floating point type. Use the half of the diff as the |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
276 // range and consume a bool to decide whether the result |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
277 // is in the first of the second part of the diff. |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
278 range = (max / 2.0) - (min / 2.0); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
279 if (ConsumeBool()) { |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
280 result += range; |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
281 } |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
282 } else { |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
283 range = max - min; |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
284 } |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
285 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
286 return result + range * ConsumeProbability<T>(); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
287 } |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
288 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
289 // Reports the remaining bytes available for fuzzed input. |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
290 size_t remaining_bytes() |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
291 { |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
292 return remaining_bytes_; |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
293 } |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
294 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
295 private: |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
296 FuzzedDataProvider(const FuzzedDataProvider &) = delete; |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
297 FuzzedDataProvider &operator=(const FuzzedDataProvider &) = delete; |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
298 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
299 void Advance(size_t num_bytes) |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
300 { |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
301 if (num_bytes > remaining_bytes_) |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
302 abort(); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
303 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
304 data_ptr_ += num_bytes; |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
305 remaining_bytes_ -= num_bytes; |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
306 } |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
307 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
308 template <typename T> |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
309 std::vector<T> ConsumeBytes(size_t size, size_t num_bytes_to_consume) |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
310 { |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
311 static_assert(sizeof(T) == sizeof(uint8_t), |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
312 "Incompatible data type."); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
313 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
314 // The point of using the size-based constructor below is to |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
315 // increase the odds of having a vector object with capacity |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
316 // being equal to the length. That part is always implementation |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
317 // specific, but at least both libc++ and libstdc++ allocate the |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
318 // requested number of bytes in that constructor, which seems to |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
319 // be a natural choice for other implementations as well. To |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
320 // increase the odds even more, we also call |shrink_to_fit| |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
321 // below. |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
322 std::vector<T> result(size); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
323 if (size == 0) { |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
324 if (num_bytes_to_consume != 0) |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
325 abort(); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
326 return result; |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
327 } |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
328 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
329 std::memcpy(result.data(), data_ptr_, num_bytes_to_consume); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
330 Advance(num_bytes_to_consume); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
331 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
332 // Even though |shrink_to_fit| is also implementation specific, |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
333 // we expect it to provide an additional assurance in case |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
334 // vector's constructor allocated a buffer which is larger than |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
335 // the actual amount of data we put inside it. |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
336 result.shrink_to_fit(); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
337 return result; |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
338 } |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
339 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
340 template <typename TS, typename TU> TS ConvertUnsignedToSigned(TU value) |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
341 { |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
342 static_assert(sizeof(TS) == sizeof(TU), |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
343 "Incompatible data types."); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
344 static_assert(!std::numeric_limits<TU>::is_signed, |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
345 "Source type must be unsigned."); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
346 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
347 // TODO(Dor1s): change to `if constexpr` once C++17 becomes |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
348 // mainstream. |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
349 if (std::numeric_limits<TS>::is_modulo) |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
350 return static_cast<TS>(value); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
351 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
352 // Avoid using implementation-defined unsigned to signer |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
353 // conversions. To learn more, see |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
354 // https://stackoverflow.com/questions/13150449. |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
355 if (value <= std::numeric_limits<TS>::max()) { |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
356 return static_cast<TS>(value); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
357 } else { |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
358 constexpr auto TS_min = std::numeric_limits<TS>::min(); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
359 return TS_min + static_cast<char>(value - TS_min); |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
360 } |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
361 } |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
362 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
363 const uint8_t *data_ptr_; |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
364 size_t remaining_bytes_; |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
365 }; |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
366 |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
367 #endif // LLVM_FUZZER_FUZZED_DATA_PROVIDER_H_ |
5a9e2ae9899b
fuzz: use a more standard approach to allow local builds of fuzzers
Augie Fackler <augie@google.com>
parents:
diff
changeset
|
368 // no-check-code since this is from a third party |