Home | History | Annotate | Download | only in Fuzzer
      1 //===- FuzzerUtil.cpp - Misc utils ----------------------------------------===//
      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 // Misc utils.
     10 //===----------------------------------------------------------------------===//
     11 
     12 #include "FuzzerInternal.h"
     13 #include <sstream>
     14 #include <iomanip>
     15 #include <sys/resource.h>
     16 #include <sys/time.h>
     17 #include <sys/types.h>
     18 #include <sys/syscall.h>
     19 #include <cassert>
     20 #include <chrono>
     21 #include <cstring>
     22 #include <signal.h>
     23 #include <sstream>
     24 #include <unistd.h>
     25 #include <errno.h>
     26 #include <thread>
     27 
     28 namespace fuzzer {
     29 
     30 void PrintHexArray(const uint8_t *Data, size_t Size,
     31                    const char *PrintAfter) {
     32   for (size_t i = 0; i < Size; i++)
     33     Printf("0x%x,", (unsigned)Data[i]);
     34   Printf("%s", PrintAfter);
     35 }
     36 
     37 void Print(const Unit &v, const char *PrintAfter) {
     38   PrintHexArray(v.data(), v.size(), PrintAfter);
     39 }
     40 
     41 void PrintASCIIByte(uint8_t Byte) {
     42   if (Byte == '\\')
     43     Printf("\\\\");
     44   else if (Byte == '"')
     45     Printf("\\\"");
     46   else if (Byte >= 32 && Byte < 127)
     47     Printf("%c", Byte);
     48   else
     49     Printf("\\x%02x", Byte);
     50 }
     51 
     52 void PrintASCII(const uint8_t *Data, size_t Size, const char *PrintAfter) {
     53   for (size_t i = 0; i < Size; i++)
     54     PrintASCIIByte(Data[i]);
     55   Printf("%s", PrintAfter);
     56 }
     57 
     58 void PrintASCII(const Word &W, const char *PrintAfter) {
     59   PrintASCII(W.data(), W.size(), PrintAfter);
     60 }
     61 
     62 void PrintASCII(const Unit &U, const char *PrintAfter) {
     63   PrintASCII(U.data(), U.size(), PrintAfter);
     64 }
     65 
     66 std::string Hash(const Unit &U) {
     67   uint8_t Hash[kSHA1NumBytes];
     68   ComputeSHA1(U.data(), U.size(), Hash);
     69   std::stringstream SS;
     70   for (int i = 0; i < kSHA1NumBytes; i++)
     71     SS << std::hex << std::setfill('0') << std::setw(2) << (unsigned)Hash[i];
     72   return SS.str();
     73 }
     74 
     75 static void AlarmHandler(int, siginfo_t *, void *) {
     76   Fuzzer::StaticAlarmCallback();
     77 }
     78 
     79 static void CrashHandler(int, siginfo_t *, void *) {
     80   Fuzzer::StaticCrashSignalCallback();
     81 }
     82 
     83 static void InterruptHandler(int, siginfo_t *, void *) {
     84   Fuzzer::StaticInterruptCallback();
     85 }
     86 
     87 static void SetSigaction(int signum,
     88                          void (*callback)(int, siginfo_t *, void *)) {
     89   struct sigaction sigact;
     90   memset(&sigact, 0, sizeof(sigact));
     91   sigact.sa_sigaction = callback;
     92   if (sigaction(signum, &sigact, 0)) {
     93     Printf("libFuzzer: sigaction failed with %d\n", errno);
     94     exit(1);
     95   }
     96 }
     97 
     98 void SetTimer(int Seconds) {
     99   struct itimerval T {{Seconds, 0}, {Seconds, 0}};
    100   if (setitimer(ITIMER_REAL, &T, nullptr)) {
    101     Printf("libFuzzer: setitimer failed with %d\n", errno);
    102     exit(1);
    103   }
    104   SetSigaction(SIGALRM, AlarmHandler);
    105 }
    106 
    107 void SetSigSegvHandler() { SetSigaction(SIGSEGV, CrashHandler); }
    108 void SetSigBusHandler() { SetSigaction(SIGBUS, CrashHandler); }
    109 void SetSigAbrtHandler() { SetSigaction(SIGABRT, CrashHandler); }
    110 void SetSigIllHandler() { SetSigaction(SIGILL, CrashHandler); }
    111 void SetSigFpeHandler() { SetSigaction(SIGFPE, CrashHandler); }
    112 void SetSigIntHandler() { SetSigaction(SIGINT, InterruptHandler); }
    113 void SetSigTermHandler() { SetSigaction(SIGTERM, InterruptHandler); }
    114 
    115 int NumberOfCpuCores() {
    116   const char *CmdLine = nullptr;
    117   if (LIBFUZZER_LINUX) {
    118     CmdLine = "nproc";
    119   } else if (LIBFUZZER_APPLE) {
    120     CmdLine = "sysctl -n hw.ncpu";
    121   } else {
    122     assert(0 && "NumberOfCpuCores() is not implemented for your platform");
    123   }
    124 
    125   FILE *F = popen(CmdLine, "r");
    126   int N = 1;
    127   if (!F || fscanf(F, "%d", &N) != 1) {
    128     Printf("WARNING: Failed to parse output of command \"%s\" in %s(). "
    129            "Assuming CPU count of 1.\n",
    130            CmdLine, __func__);
    131     N = 1;
    132   }
    133 
    134   if (pclose(F)) {
    135     Printf("WARNING: Executing command \"%s\" failed in %s(). "
    136            "Assuming CPU count of 1.\n",
    137            CmdLine, __func__);
    138     N = 1;
    139   }
    140   if (N < 1) {
    141     Printf("WARNING: Reported CPU count (%d) from command \"%s\" was invalid "
    142            "in %s(). Assuming CPU count of 1.\n",
    143            N, CmdLine, __func__);
    144     N = 1;
    145   }
    146   return N;
    147 }
    148 
    149 int ExecuteCommand(const std::string &Command) {
    150   return system(Command.c_str());
    151 }
    152 
    153 bool ToASCII(uint8_t *Data, size_t Size) {
    154   bool Changed = false;
    155   for (size_t i = 0; i < Size; i++) {
    156     uint8_t &X = Data[i];
    157     auto NewX = X;
    158     NewX &= 127;
    159     if (!isspace(NewX) && !isprint(NewX))
    160       NewX = ' ';
    161     Changed |= NewX != X;
    162     X = NewX;
    163   }
    164   return Changed;
    165 }
    166 
    167 bool IsASCII(const Unit &U) { return IsASCII(U.data(), U.size()); }
    168 
    169 bool IsASCII(const uint8_t *Data, size_t Size) {
    170   for (size_t i = 0; i < Size; i++)
    171     if (!(isprint(Data[i]) || isspace(Data[i]))) return false;
    172   return true;
    173 }
    174 
    175 bool ParseOneDictionaryEntry(const std::string &Str, Unit *U) {
    176   U->clear();
    177   if (Str.empty()) return false;
    178   size_t L = 0, R = Str.size() - 1;  // We are parsing the range [L,R].
    179   // Skip spaces from both sides.
    180   while (L < R && isspace(Str[L])) L++;
    181   while (R > L && isspace(Str[R])) R--;
    182   if (R - L < 2) return false;
    183   // Check the closing "
    184   if (Str[R] != '"') return false;
    185   R--;
    186   // Find the opening "
    187   while (L < R && Str[L] != '"') L++;
    188   if (L >= R) return false;
    189   assert(Str[L] == '\"');
    190   L++;
    191   assert(L <= R);
    192   for (size_t Pos = L; Pos <= R; Pos++) {
    193     uint8_t V = (uint8_t)Str[Pos];
    194     if (!isprint(V) && !isspace(V)) return false;
    195     if (V =='\\') {
    196       // Handle '\\'
    197       if (Pos + 1 <= R && (Str[Pos + 1] == '\\' || Str[Pos + 1] == '"')) {
    198         U->push_back(Str[Pos + 1]);
    199         Pos++;
    200         continue;
    201       }
    202       // Handle '\xAB'
    203       if (Pos + 3 <= R && Str[Pos + 1] == 'x'
    204            && isxdigit(Str[Pos + 2]) && isxdigit(Str[Pos + 3])) {
    205         char Hex[] = "0xAA";
    206         Hex[2] = Str[Pos + 2];
    207         Hex[3] = Str[Pos + 3];
    208         U->push_back(strtol(Hex, nullptr, 16));
    209         Pos += 3;
    210         continue;
    211       }
    212       return false;  // Invalid escape.
    213     } else {
    214       // Any other character.
    215       U->push_back(V);
    216     }
    217   }
    218   return true;
    219 }
    220 
    221 bool ParseDictionaryFile(const std::string &Text, std::vector<Unit> *Units) {
    222   if (Text.empty()) {
    223     Printf("ParseDictionaryFile: file does not exist or is empty\n");
    224     return false;
    225   }
    226   std::istringstream ISS(Text);
    227   Units->clear();
    228   Unit U;
    229   int LineNo = 0;
    230   std::string S;
    231   while (std::getline(ISS, S, '\n')) {
    232     LineNo++;
    233     size_t Pos = 0;
    234     while (Pos < S.size() && isspace(S[Pos])) Pos++;  // Skip spaces.
    235     if (Pos == S.size()) continue;  // Empty line.
    236     if (S[Pos] == '#') continue;  // Comment line.
    237     if (ParseOneDictionaryEntry(S, &U)) {
    238       Units->push_back(U);
    239     } else {
    240       Printf("ParseDictionaryFile: error in line %d\n\t\t%s\n", LineNo,
    241              S.c_str());
    242       return false;
    243     }
    244   }
    245   return true;
    246 }
    247 
    248 void SleepSeconds(int Seconds) {
    249   std::this_thread::sleep_for(std::chrono::seconds(Seconds));
    250 }
    251 
    252 int GetPid() { return getpid(); }
    253 
    254 std::string Base64(const Unit &U) {
    255   static const char Table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    256                               "abcdefghijklmnopqrstuvwxyz"
    257                               "0123456789+/";
    258   std::string Res;
    259   size_t i;
    260   for (i = 0; i + 2 < U.size(); i += 3) {
    261     uint32_t x = (U[i] << 16) + (U[i + 1] << 8) + U[i + 2];
    262     Res += Table[(x >> 18) & 63];
    263     Res += Table[(x >> 12) & 63];
    264     Res += Table[(x >> 6) & 63];
    265     Res += Table[x & 63];
    266   }
    267   if (i + 1 == U.size()) {
    268     uint32_t x = (U[i] << 16);
    269     Res += Table[(x >> 18) & 63];
    270     Res += Table[(x >> 12) & 63];
    271     Res += "==";
    272   } else if (i + 2 == U.size()) {
    273     uint32_t x = (U[i] << 16) + (U[i + 1] << 8);
    274     Res += Table[(x >> 18) & 63];
    275     Res += Table[(x >> 12) & 63];
    276     Res += Table[(x >> 6) & 63];
    277     Res += "=";
    278   }
    279   return Res;
    280 }
    281 
    282 size_t GetPeakRSSMb() {
    283   struct rusage usage;
    284   if (getrusage(RUSAGE_SELF, &usage))
    285     return 0;
    286   if (LIBFUZZER_LINUX) {
    287     // ru_maxrss is in KiB
    288     return usage.ru_maxrss >> 10;
    289   } else if (LIBFUZZER_APPLE) {
    290     // ru_maxrss is in bytes
    291     return usage.ru_maxrss >> 20;
    292   }
    293   assert(0 && "GetPeakRSSMb() is not implemented for your platform");
    294   return 0;
    295 }
    296 
    297 }  // namespace fuzzer
    298