Home | History | Annotate | Download | only in Fuzzer
      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