1 //===- FuzzerAdapter.h - Arbitrary function Fuzzer adapter -------*- C++ -*===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // W A R N I N G : E X P E R I M E N T A L. 11 // 12 // Defines an adapter to fuzz functions with (almost) arbitrary signatures. 13 //===----------------------------------------------------------------------===// 14 15 #ifndef LLVM_FUZZER_ADAPTER_H 16 #define LLVM_FUZZER_ADAPTER_H 17 18 #include <stddef.h> 19 #include <stdint.h> 20 21 #include <algorithm> 22 #include <string> 23 #include <tuple> 24 #include <vector> 25 26 namespace fuzzer { 27 28 /// Unpacks bytes from \p Data according to \p F argument types 29 /// and calls the function. 30 /// Use to automatically adapt LLVMFuzzerTestOneInput interface to 31 /// a specific function. 32 /// Supported argument types: primitive types, std::vector<uint8_t>. 33 template <typename Fn> bool Adapt(Fn F, const uint8_t *Data, size_t Size); 34 35 // The implementation performs several steps: 36 // - function argument types are obtained (Args...) 37 // - data is unpacked into std::tuple<Args...> one by one 38 // - function is called with std::tuple<Args...> containing arguments. 39 namespace impl { 40 41 // Single argument unpacking. 42 43 template <typename T> 44 size_t UnpackPrimitive(const uint8_t *Data, size_t Size, T *Value) { 45 if (Size < sizeof(T)) 46 return Size; 47 *Value = *reinterpret_cast<const T *>(Data); 48 return Size - sizeof(T); 49 } 50 51 /// Unpacks into a given Value and returns the Size - num_consumed_bytes. 52 /// Return value equal to Size signals inability to unpack the data (typically 53 /// because there are not enough bytes). 54 template <typename T> 55 size_t UnpackSingle(const uint8_t *Data, size_t Size, T *Value); 56 57 #define UNPACK_SINGLE_PRIMITIVE(Type) \ 58 template <> \ 59 size_t UnpackSingle<Type>(const uint8_t *Data, size_t Size, Type *Value) { \ 60 return UnpackPrimitive(Data, Size, Value); \ 61 } 62 63 UNPACK_SINGLE_PRIMITIVE(char) 64 UNPACK_SINGLE_PRIMITIVE(signed char) 65 UNPACK_SINGLE_PRIMITIVE(unsigned char) 66 67 UNPACK_SINGLE_PRIMITIVE(short int) 68 UNPACK_SINGLE_PRIMITIVE(unsigned short int) 69 70 UNPACK_SINGLE_PRIMITIVE(int) 71 UNPACK_SINGLE_PRIMITIVE(unsigned int) 72 73 UNPACK_SINGLE_PRIMITIVE(long int) 74 UNPACK_SINGLE_PRIMITIVE(unsigned long int) 75 76 UNPACK_SINGLE_PRIMITIVE(bool) 77 UNPACK_SINGLE_PRIMITIVE(wchar_t) 78 79 UNPACK_SINGLE_PRIMITIVE(float) 80 UNPACK_SINGLE_PRIMITIVE(double) 81 UNPACK_SINGLE_PRIMITIVE(long double) 82 83 #undef UNPACK_SINGLE_PRIMITIVE 84 85 template <> 86 size_t UnpackSingle<std::vector<uint8_t>>(const uint8_t *Data, size_t Size, 87 std::vector<uint8_t> *Value) { 88 if (Size < 1) 89 return Size; 90 size_t Len = std::min(static_cast<size_t>(*Data), Size - 1); 91 std::vector<uint8_t> V(Data + 1, Data + 1 + Len); 92 Value->swap(V); 93 return Size - Len - 1; 94 } 95 96 template <> 97 size_t UnpackSingle<std::string>(const uint8_t *Data, size_t Size, 98 std::string *Value) { 99 if (Size < 1) 100 return Size; 101 size_t Len = std::min(static_cast<size_t>(*Data), Size - 1); 102 std::string S(Data + 1, Data + 1 + Len); 103 Value->swap(S); 104 return Size - Len - 1; 105 } 106 107 // Unpacking into arbitrary tuple. 108 109 // Recursion guard. 110 template <int N, typename TupleT> 111 typename std::enable_if<N == std::tuple_size<TupleT>::value, bool>::type 112 UnpackImpl(const uint8_t *Data, size_t Size, TupleT *Tuple) { 113 return true; 114 } 115 116 // Unpack tuple elements starting from Nth. 117 template <int N, typename TupleT> 118 typename std::enable_if<N < std::tuple_size<TupleT>::value, bool>::type 119 UnpackImpl(const uint8_t *Data, size_t Size, TupleT *Tuple) { 120 size_t NewSize = UnpackSingle(Data, Size, &std::get<N>(*Tuple)); 121 if (NewSize == Size) { 122 return false; 123 } 124 125 return UnpackImpl<N + 1, TupleT>(Data + (Size - NewSize), NewSize, Tuple); 126 } 127 128 // Unpacks into arbitrary tuple and returns true if successful. 129 template <typename... Args> 130 bool Unpack(const uint8_t *Data, size_t Size, std::tuple<Args...> *Tuple) { 131 return UnpackImpl<0, std::tuple<Args...>>(Data, Size, Tuple); 132 } 133 134 // Helper integer sequence templates. 135 136 template <int...> struct Seq {}; 137 138 template <int N, int... S> struct GenSeq : GenSeq<N - 1, N - 1, S...> {}; 139 140 // GenSeq<N>::type is Seq<0, 1, ..., N-1> 141 template <int... S> struct GenSeq<0, S...> { typedef Seq<S...> type; }; 142 143 // Function signature introspection. 144 145 template <typename T> struct FnTraits {}; 146 147 template <typename ReturnType, typename... Args> 148 struct FnTraits<ReturnType (*)(Args...)> { 149 enum { Arity = sizeof...(Args) }; 150 typedef std::tuple<Args...> ArgsTupleT; 151 }; 152 153 // Calling a function with arguments in a tuple. 154 155 template <typename Fn, int... S> 156 void ApplyImpl(Fn F, const typename FnTraits<Fn>::ArgsTupleT &Params, 157 Seq<S...>) { 158 F(std::get<S>(Params)...); 159 } 160 161 template <typename Fn> 162 void Apply(Fn F, const typename FnTraits<Fn>::ArgsTupleT &Params) { 163 // S is Seq<0, ..., Arity-1> 164 auto S = typename GenSeq<FnTraits<Fn>::Arity>::type(); 165 ApplyImpl(F, Params, S); 166 } 167 168 // Unpacking data into arguments tuple of correct type and calling the function. 169 template <typename Fn> 170 bool UnpackAndApply(Fn F, const uint8_t *Data, size_t Size) { 171 typename FnTraits<Fn>::ArgsTupleT Tuple; 172 if (!Unpack(Data, Size, &Tuple)) 173 return false; 174 175 Apply(F, Tuple); 176 return true; 177 } 178 179 } // namespace impl 180 181 template <typename Fn> bool Adapt(Fn F, const uint8_t *Data, size_t Size) { 182 return impl::UnpackAndApply(F, Data, Size); 183 } 184 185 } // namespace fuzzer 186 187 #endif 188