Home | History | Annotate | Download | only in Fuzzer
      1 //===- FuzzerTraceState.cpp - Trace-based fuzzer mutator ------------------===//
      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 // This file implements a mutation algorithm based on instruction traces and
     10 // on taint analysis feedback from DFSan.
     11 //
     12 // Instruction traces are special hooks inserted by the compiler around
     13 // interesting instructions. Currently supported traces:
     14 //   * __sanitizer_cov_trace_cmp -- inserted before every ICMP instruction,
     15 //    receives the type, size and arguments of ICMP.
     16 //
     17 // Every time a traced event is intercepted we analyse the data involved
     18 // in the event and suggest a mutation for future executions.
     19 // For example if 4 bytes of data that derive from input bytes {4,5,6,7}
     20 // are compared with a constant 12345,
     21 // we try to insert 12345, 12344, 12346 into bytes
     22 // {4,5,6,7} of the next fuzzed inputs.
     23 //
     24 // The fuzzer can work only with the traces, or with both traces and DFSan.
     25 //
     26 // DataFlowSanitizer (DFSan) is a tool for
     27 // generalised dynamic data flow (taint) analysis:
     28 // http://clang.llvm.org/docs/DataFlowSanitizer.html .
     29 //
     30 // The approach with DFSan-based fuzzing has some similarity to
     31 // "Taint-based Directed Whitebox Fuzzing"
     32 // by Vijay Ganesh & Tim Leek & Martin Rinard:
     33 // http://dspace.mit.edu/openaccess-disseminate/1721.1/59320,
     34 // but it uses a full blown LLVM IR taint analysis and separate instrumentation
     35 // to analyze all of the "attack points" at once.
     36 //
     37 // Workflow with DFSan:
     38 //   * lib/Fuzzer/Fuzzer*.cpp is compiled w/o any instrumentation.
     39 //   * The code under test is compiled with DFSan *and* with instruction traces.
     40 //   * Every call to HOOK(a,b) is replaced by DFSan with
     41 //     __dfsw_HOOK(a, b, label(a), label(b)) so that __dfsw_HOOK
     42 //     gets all the taint labels for the arguments.
     43 //   * At the Fuzzer startup we assign a unique DFSan label
     44 //     to every byte of the input string (Fuzzer::CurrentUnitData) so that
     45 //     for any chunk of data we know which input bytes it has derived from.
     46 //   * The __dfsw_* functions (implemented in this file) record the
     47 //     parameters (i.e. the application data and the corresponding taint labels)
     48 //     in a global state.
     49 //
     50 // Parts of this code will not function when DFSan is not linked in.
     51 // Instead of using ifdefs and thus requiring a separate build of lib/Fuzzer
     52 // we redeclare the dfsan_* interface functions as weak and check if they
     53 // are nullptr before calling.
     54 // If this approach proves to be useful we may add attribute(weak) to the
     55 // dfsan declarations in dfsan_interface.h
     56 //
     57 // This module is in the "proof of concept" stage.
     58 // It is capable of solving only the simplest puzzles
     59 // like test/dfsan/DFSanSimpleCmpTest.cpp.
     60 //===----------------------------------------------------------------------===//
     61 
     62 /* Example of manual usage (-fsanitize=dataflow is optional):
     63 (
     64   cd $LLVM/lib/Fuzzer/
     65   clang  -fPIC -c -g -O2 -std=c++11 Fuzzer*.cpp
     66   clang++ -O0 -std=c++11 -fsanitize-coverage=edge,trace-cmp \
     67     -fsanitize=dataflow \
     68     test/SimpleCmpTest.cpp Fuzzer*.o
     69   ./a.out -use_traces=1
     70 )
     71 */
     72 
     73 #include "FuzzerDFSan.h"
     74 #include "FuzzerInternal.h"
     75 
     76 #include <algorithm>
     77 #include <cstring>
     78 #include <thread>
     79 #include <map>
     80 
     81 #if !LLVM_FUZZER_SUPPORTS_DFSAN
     82 // Stubs for dfsan for platforms where dfsan does not exist and weak
     83 // functions don't work.
     84 extern "C" {
     85 dfsan_label dfsan_create_label(const char *desc, void *userdata) { return 0; }
     86 void dfsan_set_label(dfsan_label label, void *addr, size_t size) {}
     87 void dfsan_add_label(dfsan_label label, void *addr, size_t size) {}
     88 const struct dfsan_label_info *dfsan_get_label_info(dfsan_label label) {
     89   return nullptr;
     90 }
     91 dfsan_label dfsan_read_label(const void *addr, size_t size) { return 0; }
     92 }  // extern "C"
     93 #endif  // !LLVM_FUZZER_SUPPORTS_DFSAN
     94 
     95 namespace fuzzer {
     96 
     97 // These values are copied from include/llvm/IR/InstrTypes.h.
     98 // We do not include the LLVM headers here to remain independent.
     99 // If these values ever change, an assertion in ComputeCmp will fail.
    100 enum Predicate {
    101   ICMP_EQ = 32,  ///< equal
    102   ICMP_NE = 33,  ///< not equal
    103   ICMP_UGT = 34, ///< unsigned greater than
    104   ICMP_UGE = 35, ///< unsigned greater or equal
    105   ICMP_ULT = 36, ///< unsigned less than
    106   ICMP_ULE = 37, ///< unsigned less or equal
    107   ICMP_SGT = 38, ///< signed greater than
    108   ICMP_SGE = 39, ///< signed greater or equal
    109   ICMP_SLT = 40, ///< signed less than
    110   ICMP_SLE = 41, ///< signed less or equal
    111 };
    112 
    113 template <class U, class S>
    114 bool ComputeCmp(size_t CmpType, U Arg1, U Arg2) {
    115   switch(CmpType) {
    116     case ICMP_EQ : return Arg1 == Arg2;
    117     case ICMP_NE : return Arg1 != Arg2;
    118     case ICMP_UGT: return Arg1 > Arg2;
    119     case ICMP_UGE: return Arg1 >= Arg2;
    120     case ICMP_ULT: return Arg1 < Arg2;
    121     case ICMP_ULE: return Arg1 <= Arg2;
    122     case ICMP_SGT: return (S)Arg1 > (S)Arg2;
    123     case ICMP_SGE: return (S)Arg1 >= (S)Arg2;
    124     case ICMP_SLT: return (S)Arg1 < (S)Arg2;
    125     case ICMP_SLE: return (S)Arg1 <= (S)Arg2;
    126     default: assert(0 && "unsupported CmpType");
    127   }
    128   return false;
    129 }
    130 
    131 static bool ComputeCmp(size_t CmpSize, size_t CmpType, uint64_t Arg1,
    132                        uint64_t Arg2) {
    133   if (CmpSize == 8) return ComputeCmp<uint64_t, int64_t>(CmpType, Arg1, Arg2);
    134   if (CmpSize == 4) return ComputeCmp<uint32_t, int32_t>(CmpType, Arg1, Arg2);
    135   if (CmpSize == 2) return ComputeCmp<uint16_t, int16_t>(CmpType, Arg1, Arg2);
    136   if (CmpSize == 1) return ComputeCmp<uint8_t, int8_t>(CmpType, Arg1, Arg2);
    137   // Other size, ==
    138   if (CmpType == ICMP_EQ) return Arg1 == Arg2;
    139   // assert(0 && "unsupported cmp and type size combination");
    140   return true;
    141 }
    142 
    143 // As a simplification we use the range of input bytes instead of a set of input
    144 // bytes.
    145 struct LabelRange {
    146   uint16_t Beg, End;  // Range is [Beg, End), thus Beg==End is an empty range.
    147 
    148   LabelRange(uint16_t Beg = 0, uint16_t End = 0) : Beg(Beg), End(End) {}
    149 
    150   static LabelRange Join(LabelRange LR1, LabelRange LR2) {
    151     if (LR1.Beg == LR1.End) return LR2;
    152     if (LR2.Beg == LR2.End) return LR1;
    153     return {std::min(LR1.Beg, LR2.Beg), std::max(LR1.End, LR2.End)};
    154   }
    155   LabelRange &Join(LabelRange LR) {
    156     return *this = Join(*this, LR);
    157   }
    158   static LabelRange Singleton(const dfsan_label_info *LI) {
    159     uint16_t Idx = (uint16_t)(uintptr_t)LI->userdata;
    160     assert(Idx > 0);
    161     return {(uint16_t)(Idx - 1), Idx};
    162   }
    163 };
    164 
    165 // For now, very simple: put Size bytes of Data at position Pos.
    166 struct TraceBasedMutation {
    167   uint32_t Pos;
    168   Word W;
    169 };
    170 
    171 // Declared as static globals for faster checks inside the hooks.
    172 static bool RecordingTraces = false;
    173 static bool RecordingMemcmp = false;
    174 
    175 class TraceState {
    176 public:
    177   TraceState(MutationDispatcher &MD, const FuzzingOptions &Options,
    178              const Fuzzer *F)
    179       : MD(MD), Options(Options), F(F) {}
    180 
    181   LabelRange GetLabelRange(dfsan_label L);
    182   void DFSanCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType,
    183                         uint64_t Arg1, uint64_t Arg2, dfsan_label L1,
    184                         dfsan_label L2);
    185   void DFSanMemcmpCallback(size_t CmpSize, const uint8_t *Data1,
    186                            const uint8_t *Data2, dfsan_label L1,
    187                            dfsan_label L2);
    188   void DFSanSwitchCallback(uint64_t PC, size_t ValSizeInBits, uint64_t Val,
    189                            size_t NumCases, uint64_t *Cases, dfsan_label L);
    190   void TraceCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType,
    191                         uint64_t Arg1, uint64_t Arg2);
    192   void TraceMemcmpCallback(size_t CmpSize, const uint8_t *Data1,
    193                            const uint8_t *Data2);
    194 
    195   void TraceSwitchCallback(uintptr_t PC, size_t ValSizeInBits, uint64_t Val,
    196                            size_t NumCases, uint64_t *Cases);
    197   int TryToAddDesiredData(uint64_t PresentData, uint64_t DesiredData,
    198                           size_t DataSize);
    199   int TryToAddDesiredData(const uint8_t *PresentData,
    200                           const uint8_t *DesiredData, size_t DataSize);
    201 
    202   void StartTraceRecording() {
    203     if (!Options.UseTraces && !Options.UseMemcmp)
    204       return;
    205     RecordingTraces = Options.UseTraces;
    206     RecordingMemcmp = Options.UseMemcmp;
    207     NumMutations = 0;
    208     MD.ClearAutoDictionary();
    209   }
    210 
    211   void StopTraceRecording() {
    212     if (!RecordingTraces && !RecordingMemcmp)
    213       return;
    214     RecordingTraces = false;
    215     RecordingMemcmp = false;
    216     for (size_t i = 0; i < NumMutations; i++) {
    217       auto &M = Mutations[i];
    218       if (Options.Verbosity >= 2) {
    219         AutoDictUnitCounts[M.W]++;
    220         AutoDictAdds++;
    221         if ((AutoDictAdds & (AutoDictAdds - 1)) == 0) {
    222           typedef std::pair<size_t, Word> CU;
    223           std::vector<CU> CountedUnits;
    224           for (auto &I : AutoDictUnitCounts)
    225             CountedUnits.push_back(std::make_pair(I.second, I.first));
    226           std::sort(CountedUnits.begin(), CountedUnits.end(),
    227                     [](const CU &a, const CU &b) { return a.first > b.first; });
    228           Printf("AutoDict:\n");
    229           for (auto &I : CountedUnits) {
    230             Printf("   %zd ", I.first);
    231             PrintASCII(I.second);
    232             Printf("\n");
    233           }
    234         }
    235       }
    236       MD.AddWordToAutoDictionary(M.W, M.Pos);
    237     }
    238   }
    239 
    240   void AddMutation(uint32_t Pos, uint32_t Size, const uint8_t *Data) {
    241     if (NumMutations >= kMaxMutations) return;
    242     auto &M = Mutations[NumMutations++];
    243     M.Pos = Pos;
    244     M.W.Set(Data, Size);
    245   }
    246 
    247   void AddMutation(uint32_t Pos, uint32_t Size, uint64_t Data) {
    248     assert(Size <= sizeof(Data));
    249     AddMutation(Pos, Size, reinterpret_cast<uint8_t*>(&Data));
    250   }
    251 
    252   void EnsureDfsanLabels(size_t Size) {
    253     for (; LastDfsanLabel < Size; LastDfsanLabel++) {
    254       dfsan_label L = dfsan_create_label("input", (void *)(LastDfsanLabel + 1));
    255       // We assume that no one else has called dfsan_create_label before.
    256       if (L != LastDfsanLabel + 1) {
    257         Printf("DFSan labels are not starting from 1, exiting\n");
    258         exit(1);
    259       }
    260     }
    261   }
    262 
    263  private:
    264   bool IsTwoByteData(uint64_t Data) {
    265     int64_t Signed = static_cast<int64_t>(Data);
    266     Signed >>= 16;
    267     return Signed == 0 || Signed == -1L;
    268   }
    269 
    270   // We don't want to create too many trace-based mutations as it is both
    271   // expensive and useless. So after some number of mutations is collected,
    272   // start rejecting some of them. The more there are mutations the more we
    273   // reject.
    274   bool WantToHandleOneMoreMutation() {
    275     const size_t FirstN = 64;
    276     // Gladly handle first N mutations.
    277     if (NumMutations <= FirstN) return true;
    278     size_t Diff = NumMutations - FirstN;
    279     size_t DiffLog = sizeof(long) * 8 - __builtin_clzl((long)Diff);
    280     assert(DiffLog > 0 && DiffLog < 64);
    281     bool WantThisOne = MD.GetRand()(1 << DiffLog) == 0;  // 1 out of DiffLog.
    282     return WantThisOne;
    283   }
    284 
    285   static const size_t kMaxMutations = 1 << 16;
    286   size_t NumMutations;
    287   TraceBasedMutation Mutations[kMaxMutations];
    288   LabelRange LabelRanges[1 << (sizeof(dfsan_label) * 8)];
    289   size_t LastDfsanLabel = 0;
    290   MutationDispatcher &MD;
    291   const FuzzingOptions Options;
    292   const Fuzzer *F;
    293   std::map<Word, size_t> AutoDictUnitCounts;
    294   size_t AutoDictAdds = 0;
    295 };
    296 
    297 
    298 LabelRange TraceState::GetLabelRange(dfsan_label L) {
    299   LabelRange &LR = LabelRanges[L];
    300   if (LR.Beg < LR.End || L == 0)
    301     return LR;
    302   const dfsan_label_info *LI = dfsan_get_label_info(L);
    303   if (LI->l1 || LI->l2)
    304     return LR = LabelRange::Join(GetLabelRange(LI->l1), GetLabelRange(LI->l2));
    305   return LR = LabelRange::Singleton(LI);
    306 }
    307 
    308 void TraceState::DFSanCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType,
    309                                   uint64_t Arg1, uint64_t Arg2, dfsan_label L1,
    310                                   dfsan_label L2) {
    311   assert(ReallyHaveDFSan());
    312   if (!RecordingTraces || !F->InFuzzingThread()) return;
    313   if (L1 == 0 && L2 == 0)
    314     return;  // Not actionable.
    315   if (L1 != 0 && L2 != 0)
    316     return;  // Probably still actionable.
    317   bool Res = ComputeCmp(CmpSize, CmpType, Arg1, Arg2);
    318   uint64_t Data = L1 ? Arg2 : Arg1;
    319   LabelRange LR = L1 ? GetLabelRange(L1) : GetLabelRange(L2);
    320 
    321   for (size_t Pos = LR.Beg; Pos + CmpSize <= LR.End; Pos++) {
    322     AddMutation(Pos, CmpSize, Data);
    323     AddMutation(Pos, CmpSize, Data + 1);
    324     AddMutation(Pos, CmpSize, Data - 1);
    325   }
    326 
    327   if (CmpSize > (size_t)(LR.End - LR.Beg))
    328     AddMutation(LR.Beg, (unsigned)(LR.End - LR.Beg), Data);
    329 
    330 
    331   if (Options.Verbosity >= 3)
    332     Printf("DFSanCmpCallback: PC %lx S %zd T %zd A1 %llx A2 %llx R %d L1 %d L2 "
    333            "%d MU %zd\n",
    334            PC, CmpSize, CmpType, Arg1, Arg2, Res, L1, L2, NumMutations);
    335 }
    336 
    337 void TraceState::DFSanMemcmpCallback(size_t CmpSize, const uint8_t *Data1,
    338                                      const uint8_t *Data2, dfsan_label L1,
    339                                      dfsan_label L2) {
    340 
    341   assert(ReallyHaveDFSan());
    342   if (!RecordingMemcmp || !F->InFuzzingThread()) return;
    343   if (L1 == 0 && L2 == 0)
    344     return;  // Not actionable.
    345   if (L1 != 0 && L2 != 0)
    346     return;  // Probably still actionable.
    347 
    348   const uint8_t *Data = L1 ? Data2 : Data1;
    349   LabelRange LR = L1 ? GetLabelRange(L1) : GetLabelRange(L2);
    350   for (size_t Pos = LR.Beg; Pos + CmpSize <= LR.End; Pos++) {
    351     AddMutation(Pos, CmpSize, Data);
    352     if (Options.Verbosity >= 3)
    353       Printf("DFSanMemcmpCallback: Pos %d Size %d\n", Pos, CmpSize);
    354   }
    355 }
    356 
    357 void TraceState::DFSanSwitchCallback(uint64_t PC, size_t ValSizeInBits,
    358                                      uint64_t Val, size_t NumCases,
    359                                      uint64_t *Cases, dfsan_label L) {
    360   assert(ReallyHaveDFSan());
    361   if (!RecordingTraces || !F->InFuzzingThread()) return;
    362   if (!L) return;  // Not actionable.
    363   LabelRange LR = GetLabelRange(L);
    364   size_t ValSize = ValSizeInBits / 8;
    365   bool TryShort = IsTwoByteData(Val);
    366   for (size_t i = 0; i < NumCases; i++)
    367     TryShort &= IsTwoByteData(Cases[i]);
    368 
    369   for (size_t Pos = LR.Beg; Pos + ValSize <= LR.End; Pos++)
    370     for (size_t i = 0; i < NumCases; i++)
    371       AddMutation(Pos, ValSize, Cases[i]);
    372 
    373   if (TryShort)
    374     for (size_t Pos = LR.Beg; Pos + 2 <= LR.End; Pos++)
    375       for (size_t i = 0; i < NumCases; i++)
    376         AddMutation(Pos, 2, Cases[i]);
    377 
    378   if (Options.Verbosity >= 3)
    379     Printf("DFSanSwitchCallback: PC %lx Val %zd SZ %zd # %zd L %d: {%d, %d} "
    380            "TryShort %d\n",
    381            PC, Val, ValSize, NumCases, L, LR.Beg, LR.End, TryShort);
    382 }
    383 
    384 int TraceState::TryToAddDesiredData(uint64_t PresentData, uint64_t DesiredData,
    385                                     size_t DataSize) {
    386   if (NumMutations >= kMaxMutations || !WantToHandleOneMoreMutation()) return 0;
    387   const uint8_t *UnitData;
    388   auto UnitSize = F->GetCurrentUnitInFuzzingThead(&UnitData);
    389   int Res = 0;
    390   const uint8_t *Beg = UnitData;
    391   const uint8_t *End = Beg + UnitSize;
    392   for (const uint8_t *Cur = Beg; Cur < End; Cur++) {
    393     Cur = (uint8_t *)memmem(Cur, End - Cur, &PresentData, DataSize);
    394     if (!Cur)
    395       break;
    396     size_t Pos = Cur - Beg;
    397     assert(Pos < UnitSize);
    398     AddMutation(Pos, DataSize, DesiredData);
    399     AddMutation(Pos, DataSize, DesiredData + 1);
    400     AddMutation(Pos, DataSize, DesiredData - 1);
    401     Res++;
    402   }
    403   return Res;
    404 }
    405 
    406 int TraceState::TryToAddDesiredData(const uint8_t *PresentData,
    407                                     const uint8_t *DesiredData,
    408                                     size_t DataSize) {
    409   if (NumMutations >= kMaxMutations || !WantToHandleOneMoreMutation()) return 0;
    410   const uint8_t *UnitData;
    411   auto UnitSize = F->GetCurrentUnitInFuzzingThead(&UnitData);
    412   int Res = 0;
    413   const uint8_t *Beg = UnitData;
    414   const uint8_t *End = Beg + UnitSize;
    415   for (const uint8_t *Cur = Beg; Cur < End; Cur++) {
    416     Cur = (uint8_t *)memmem(Cur, End - Cur, PresentData, DataSize);
    417     if (!Cur)
    418       break;
    419     size_t Pos = Cur - Beg;
    420     assert(Pos < UnitSize);
    421     AddMutation(Pos, DataSize, DesiredData);
    422     Res++;
    423   }
    424   return Res;
    425 }
    426 
    427 void TraceState::TraceCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType,
    428                                   uint64_t Arg1, uint64_t Arg2) {
    429   if (!RecordingTraces || !F->InFuzzingThread()) return;
    430   if ((CmpType == ICMP_EQ || CmpType == ICMP_NE) && Arg1 == Arg2)
    431     return;  // No reason to mutate.
    432   int Added = 0;
    433   Added += TryToAddDesiredData(Arg1, Arg2, CmpSize);
    434   Added += TryToAddDesiredData(Arg2, Arg1, CmpSize);
    435   if (!Added && CmpSize == 4 && IsTwoByteData(Arg1) && IsTwoByteData(Arg2)) {
    436     Added += TryToAddDesiredData(Arg1, Arg2, 2);
    437     Added += TryToAddDesiredData(Arg2, Arg1, 2);
    438   }
    439   if (Options.Verbosity >= 3 && Added)
    440     Printf("TraceCmp %zd/%zd: %p %zd %zd\n", CmpSize, CmpType, PC, Arg1, Arg2);
    441 }
    442 
    443 void TraceState::TraceMemcmpCallback(size_t CmpSize, const uint8_t *Data1,
    444                                      const uint8_t *Data2) {
    445   if (!RecordingMemcmp || !F->InFuzzingThread()) return;
    446   CmpSize = std::min(CmpSize, Word::GetMaxSize());
    447   int Added2 = TryToAddDesiredData(Data1, Data2, CmpSize);
    448   int Added1 = TryToAddDesiredData(Data2, Data1, CmpSize);
    449   if ((Added1 || Added2) && Options.Verbosity >= 3) {
    450     Printf("MemCmp Added %d%d: ", Added1, Added2);
    451     if (Added1) PrintASCII(Data1, CmpSize);
    452     if (Added2) PrintASCII(Data2, CmpSize);
    453     Printf("\n");
    454   }
    455 }
    456 
    457 void TraceState::TraceSwitchCallback(uintptr_t PC, size_t ValSizeInBits,
    458                                      uint64_t Val, size_t NumCases,
    459                                      uint64_t *Cases) {
    460   if (!RecordingTraces || !F->InFuzzingThread()) return;
    461   size_t ValSize = ValSizeInBits / 8;
    462   bool TryShort = IsTwoByteData(Val);
    463   for (size_t i = 0; i < NumCases; i++)
    464     TryShort &= IsTwoByteData(Cases[i]);
    465 
    466   if (Options.Verbosity >= 3)
    467     Printf("TraceSwitch: %p %zd # %zd; TryShort %d\n", PC, Val, NumCases,
    468            TryShort);
    469 
    470   for (size_t i = 0; i < NumCases; i++) {
    471     TryToAddDesiredData(Val, Cases[i], ValSize);
    472     if (TryShort)
    473       TryToAddDesiredData(Val, Cases[i], 2);
    474   }
    475 }
    476 
    477 static TraceState *TS;
    478 
    479 void Fuzzer::StartTraceRecording() {
    480   if (!TS) return;
    481   TS->StartTraceRecording();
    482 }
    483 
    484 void Fuzzer::StopTraceRecording() {
    485   if (!TS) return;
    486   TS->StopTraceRecording();
    487 }
    488 
    489 void Fuzzer::AssignTaintLabels(uint8_t *Data, size_t Size) {
    490   if (!Options.UseTraces && !Options.UseMemcmp) return;
    491   if (!ReallyHaveDFSan()) return;
    492   TS->EnsureDfsanLabels(Size);
    493   for (size_t i = 0; i < Size; i++)
    494     dfsan_set_label(i + 1, &Data[i], 1);
    495 }
    496 
    497 void Fuzzer::InitializeTraceState() {
    498   if (!Options.UseTraces && !Options.UseMemcmp) return;
    499   TS = new TraceState(MD, Options, this);
    500 }
    501 
    502 static size_t InternalStrnlen(const char *S, size_t MaxLen) {
    503   size_t Len = 0;
    504   for (; Len < MaxLen && S[Len]; Len++) {}
    505   return Len;
    506 }
    507 
    508 }  // namespace fuzzer
    509 
    510 using fuzzer::TS;
    511 using fuzzer::RecordingTraces;
    512 using fuzzer::RecordingMemcmp;
    513 
    514 extern "C" {
    515 void __dfsw___sanitizer_cov_trace_cmp(uint64_t SizeAndType, uint64_t Arg1,
    516                                       uint64_t Arg2, dfsan_label L0,
    517                                       dfsan_label L1, dfsan_label L2) {
    518   if (!RecordingTraces) return;
    519   assert(L0 == 0);
    520   uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
    521   uint64_t CmpSize = (SizeAndType >> 32) / 8;
    522   uint64_t Type = (SizeAndType << 32) >> 32;
    523   TS->DFSanCmpCallback(PC, CmpSize, Type, Arg1, Arg2, L1, L2);
    524 }
    525 
    526 void __dfsw___sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases,
    527                                          dfsan_label L1, dfsan_label L2) {
    528   if (!RecordingTraces) return;
    529   uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
    530   TS->DFSanSwitchCallback(PC, Cases[1], Val, Cases[0], Cases+2, L1);
    531 }
    532 
    533 void dfsan_weak_hook_memcmp(void *caller_pc, const void *s1, const void *s2,
    534                             size_t n, dfsan_label s1_label,
    535                             dfsan_label s2_label, dfsan_label n_label) {
    536   if (!RecordingMemcmp) return;
    537   dfsan_label L1 = dfsan_read_label(s1, n);
    538   dfsan_label L2 = dfsan_read_label(s2, n);
    539   TS->DFSanMemcmpCallback(n, reinterpret_cast<const uint8_t *>(s1),
    540                           reinterpret_cast<const uint8_t *>(s2), L1, L2);
    541 }
    542 
    543 void dfsan_weak_hook_strncmp(void *caller_pc, const char *s1, const char *s2,
    544                              size_t n, dfsan_label s1_label,
    545                              dfsan_label s2_label, dfsan_label n_label) {
    546   if (!RecordingMemcmp) return;
    547   n = std::min(n, fuzzer::InternalStrnlen(s1, n));
    548   n = std::min(n, fuzzer::InternalStrnlen(s2, n));
    549   dfsan_label L1 = dfsan_read_label(s1, n);
    550   dfsan_label L2 = dfsan_read_label(s2, n);
    551   TS->DFSanMemcmpCallback(n, reinterpret_cast<const uint8_t *>(s1),
    552                           reinterpret_cast<const uint8_t *>(s2), L1, L2);
    553 }
    554 
    555 void dfsan_weak_hook_strcmp(void *caller_pc, const char *s1, const char *s2,
    556                             dfsan_label s1_label, dfsan_label s2_label) {
    557   if (!RecordingMemcmp) return;
    558   size_t Len1 = strlen(s1);
    559   size_t Len2 = strlen(s2);
    560   size_t N = std::min(Len1, Len2);
    561   if (N <= 1) return;  // Not interesting.
    562   dfsan_label L1 = dfsan_read_label(s1, Len1);
    563   dfsan_label L2 = dfsan_read_label(s2, Len2);
    564   TS->DFSanMemcmpCallback(N, reinterpret_cast<const uint8_t *>(s1),
    565                           reinterpret_cast<const uint8_t *>(s2), L1, L2);
    566 }
    567 
    568 // We may need to avoid defining weak hooks to stay compatible with older clang.
    569 #ifndef LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS
    570 # define LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS 1
    571 #endif
    572 
    573 #if LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS
    574 void __sanitizer_weak_hook_memcmp(void *caller_pc, const void *s1,
    575                                   const void *s2, size_t n, int result) {
    576   if (!RecordingMemcmp) return;
    577   if (result == 0) return;  // No reason to mutate.
    578   if (n <= 1) return;  // Not interesting.
    579   TS->TraceMemcmpCallback(n, reinterpret_cast<const uint8_t *>(s1),
    580                           reinterpret_cast<const uint8_t *>(s2));
    581 }
    582 
    583 void __sanitizer_weak_hook_strncmp(void *caller_pc, const char *s1,
    584                                    const char *s2, size_t n, int result) {
    585   if (!RecordingMemcmp) return;
    586   if (result == 0) return;  // No reason to mutate.
    587   size_t Len1 = fuzzer::InternalStrnlen(s1, n);
    588   size_t Len2 = fuzzer::InternalStrnlen(s2, n);
    589   n = std::min(n, Len1);
    590   n = std::min(n, Len2);
    591   if (n <= 1) return;  // Not interesting.
    592   TS->TraceMemcmpCallback(n, reinterpret_cast<const uint8_t *>(s1),
    593                           reinterpret_cast<const uint8_t *>(s2));
    594 }
    595 
    596 void __sanitizer_weak_hook_strcmp(void *caller_pc, const char *s1,
    597                                    const char *s2, int result) {
    598   if (!RecordingMemcmp) return;
    599   if (result == 0) return;  // No reason to mutate.
    600   size_t Len1 = strlen(s1);
    601   size_t Len2 = strlen(s2);
    602   size_t N = std::min(Len1, Len2);
    603   if (N <= 1) return;  // Not interesting.
    604   TS->TraceMemcmpCallback(N, reinterpret_cast<const uint8_t *>(s1),
    605                           reinterpret_cast<const uint8_t *>(s2));
    606 }
    607 
    608 #endif  // LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS
    609 
    610 __attribute__((visibility("default")))
    611 void __sanitizer_cov_trace_cmp(uint64_t SizeAndType, uint64_t Arg1,
    612                                uint64_t Arg2) {
    613   if (!RecordingTraces) return;
    614   uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
    615   uint64_t CmpSize = (SizeAndType >> 32) / 8;
    616   uint64_t Type = (SizeAndType << 32) >> 32;
    617   TS->TraceCmpCallback(PC, CmpSize, Type, Arg1, Arg2);
    618 }
    619 
    620 __attribute__((visibility("default")))
    621 void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) {
    622   if (!RecordingTraces) return;
    623   uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
    624   TS->TraceSwitchCallback(PC, Cases[1], Val, Cases[0], Cases + 2);
    625 }
    626 
    627 }  // extern "C"
    628