• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
PrintHexArray(const uint8_t * Data,size_t Size,const char * PrintAfter)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 
Print(const Unit & v,const char * PrintAfter)37 void Print(const Unit &v, const char *PrintAfter) {
38   PrintHexArray(v.data(), v.size(), PrintAfter);
39 }
40 
PrintASCIIByte(uint8_t Byte)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 
PrintASCII(const uint8_t * Data,size_t Size,const char * PrintAfter)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 
PrintASCII(const Word & W,const char * PrintAfter)58 void PrintASCII(const Word &W, const char *PrintAfter) {
59   PrintASCII(W.data(), W.size(), PrintAfter);
60 }
61 
PrintASCII(const Unit & U,const char * PrintAfter)62 void PrintASCII(const Unit &U, const char *PrintAfter) {
63   PrintASCII(U.data(), U.size(), PrintAfter);
64 }
65 
Hash(const Unit & U)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 
AlarmHandler(int,siginfo_t *,void *)75 static void AlarmHandler(int, siginfo_t *, void *) {
76   Fuzzer::StaticAlarmCallback();
77 }
78 
CrashHandler(int,siginfo_t *,void *)79 static void CrashHandler(int, siginfo_t *, void *) {
80   Fuzzer::StaticCrashSignalCallback();
81 }
82 
InterruptHandler(int,siginfo_t *,void *)83 static void InterruptHandler(int, siginfo_t *, void *) {
84   Fuzzer::StaticInterruptCallback();
85 }
86 
SetSigaction(int signum,void (* callback)(int,siginfo_t *,void *))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 
SetTimer(int Seconds)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 
SetSigSegvHandler()107 void SetSigSegvHandler() { SetSigaction(SIGSEGV, CrashHandler); }
SetSigBusHandler()108 void SetSigBusHandler() { SetSigaction(SIGBUS, CrashHandler); }
SetSigAbrtHandler()109 void SetSigAbrtHandler() { SetSigaction(SIGABRT, CrashHandler); }
SetSigIllHandler()110 void SetSigIllHandler() { SetSigaction(SIGILL, CrashHandler); }
SetSigFpeHandler()111 void SetSigFpeHandler() { SetSigaction(SIGFPE, CrashHandler); }
SetSigIntHandler()112 void SetSigIntHandler() { SetSigaction(SIGINT, InterruptHandler); }
SetSigTermHandler()113 void SetSigTermHandler() { SetSigaction(SIGTERM, InterruptHandler); }
114 
NumberOfCpuCores()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 
ExecuteCommand(const std::string & Command)149 int ExecuteCommand(const std::string &Command) {
150   return system(Command.c_str());
151 }
152 
ToASCII(uint8_t * Data,size_t Size)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 
IsASCII(const Unit & U)167 bool IsASCII(const Unit &U) { return IsASCII(U.data(), U.size()); }
168 
IsASCII(const uint8_t * Data,size_t Size)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 
ParseOneDictionaryEntry(const std::string & Str,Unit * U)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 
ParseDictionaryFile(const std::string & Text,std::vector<Unit> * Units)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 
SleepSeconds(int Seconds)248 void SleepSeconds(int Seconds) {
249   std::this_thread::sleep_for(std::chrono::seconds(Seconds));
250 }
251 
GetPid()252 int GetPid() { return getpid(); }
253 
Base64(const Unit & U)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 
GetPeakRSSMb()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