xref: /aosp_15_r20/external/pigweed/pw_allocator/public/pw_allocator/fuzzing.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15 
16 #include <cstddef>
17 
18 #include "pw_allocator/test_harness.h"
19 #include "pw_fuzzer/fuzztest.h"
20 
21 namespace pw::allocator::test {
22 
23 /// Returns a FuzzTest domain for producing arbitrary allocator requests.
24 ///
25 /// This method integrates with FuzzTest to use code coverage to produce guided
26 /// mutations.
27 ///
28 /// See https://github.com/google/fuzztest/blob/main/doc/domains-reference.md
29 ///
30 /// @param  max_size  Size of the largest allocation that can be requested.
31 fuzzer::Domain<Request> ArbitraryRequest(size_t max_size);
32 
33 /// Returns a FuzzTest domain for producing sequences of arbitrary allocator
34 /// requests.
35 ///
36 /// This method can be used to drive an `AllocatorTestHarness` as part of a
37 /// fuzz test.
38 ///
39 /// See https://github.com/google/fuzztest/blob/main/doc/domains-reference.md
40 ///
41 /// @param  max_size  Size of the largest allocation that can be requested.
42 template <size_t kMaxRequests, size_t kMaxSize>
ArbitraryRequests()43 auto ArbitraryRequests() {
44   return fuzzer::VectorOf<kMaxRequests>(ArbitraryRequest(kMaxSize));
45 }
46 
47 /// Builds an Request from an index and values.
48 ///
49 /// Unfortunately, the reproducer emitted by FuzzTest for vectors of
50 /// Requests cannot simply be copied and pasted. To create a
51 /// reproducer, create a `pw::Vector` of the appropriate size, and populate it
52 /// using this method with the correct index.
53 ///
54 /// For example, consider the following sample output:
55 /// @code
56 /// The test fails with input:
57 /// argument 0: {(index=0, value={0, 1}), (index=0, value={1209, 8}),
58 /// (index=2, value={9223372036854775807, 2048})}
59 ///
60 /// =================================================================
61 /// === Reproducer test
62 ///
63 /// TEST(MyAllocatorFuzzTest, NeverCrashesU16Regression) {
64 ///   NeverCrashes(
65 ///     {{0, 1}, {1209, 8}, {9223372036854775807, 2048},
66 ///   );
67 /// }
68 /// @endcode
69 ///
70 /// A valid reproducer might be:
71 /// @code{.cpp}
72 /// TEST(MyAllocatorFuzzTest, NeverCrashesU16Regression) {
73 ///   Vector<test::Request, 3> input({
74 ///     test::MakeRequest<0>(0u, 1u),
75 ///     test::MakeRequest<0>(1209u, 8u),
76 ///     test::MakeRequest<2>(9223372036854775807u, 2048u),
77 ///   });
78 ///   NeverCrashes(input);
79 // }
80 /// @endcode
81 template <size_t kIndex, typename... Args>
MakeRequest(Args...args)82 Request MakeRequest(Args... args) {
83   if constexpr (kIndex == 0) {
84     return AllocationRequest{static_cast<size_t>(args)...};
85   }
86   if constexpr (kIndex == 1) {
87     return DeallocationRequest{static_cast<size_t>(args)...};
88   }
89   if constexpr (kIndex == 2) {
90     return ReallocationRequest{static_cast<size_t>(args)...};
91   }
92   return Request();
93 }
94 
95 }  // namespace pw::allocator::test
96