blob: d845333a1699aa680104d4334d8044c399fbfd71 [file] [log] [blame]
Aaron Ballmanef116982015-01-29 16:58:29 +00001//===- 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"
Kostya Serebryany96eab652015-05-14 22:41:49 +000013#include <sstream>
14#include <iomanip>
Kostya Serebryany66ff0752016-02-26 22:42:23 +000015#include <sys/resource.h>
Aaron Ballmanef116982015-01-29 16:58:29 +000016#include <sys/time.h>
Kostya Serebryany8b8f7a32016-05-06 23:38:07 +000017#include <sys/types.h>
18#include <sys/syscall.h>
Aaron Ballmanef116982015-01-29 16:58:29 +000019#include <cassert>
Kostya Serebryany8b8f7a32016-05-06 23:38:07 +000020#include <chrono>
Aaron Ballmanef116982015-01-29 16:58:29 +000021#include <cstring>
Kostya Serebryany95b1a432016-10-19 00:12:03 +000022#include <stdio.h>
Aaron Ballmanef116982015-01-29 16:58:29 +000023#include <signal.h>
Kostya Serebryany9838b2b2015-09-03 20:23:46 +000024#include <sstream>
Kostya Serebryanyf47198a2015-05-12 22:03:34 +000025#include <unistd.h>
Dmitry Vyukov2eed1212016-03-02 09:54:40 +000026#include <errno.h>
Kostya Serebryany8b8f7a32016-05-06 23:38:07 +000027#include <thread>
Aaron Ballmanef116982015-01-29 16:58:29 +000028
29namespace fuzzer {
30
Kostya Serebryany98abb2c2016-01-13 23:46:01 +000031void PrintHexArray(const uint8_t *Data, size_t Size,
32 const char *PrintAfter) {
33 for (size_t i = 0; i < Size; i++)
34 Printf("0x%x,", (unsigned)Data[i]);
Kostya Serebryany7c180ea2015-05-23 01:22:35 +000035 Printf("%s", PrintAfter);
Aaron Ballmanef116982015-01-29 16:58:29 +000036}
37
Kostya Serebryany98abb2c2016-01-13 23:46:01 +000038void Print(const Unit &v, const char *PrintAfter) {
39 PrintHexArray(v.data(), v.size(), PrintAfter);
40}
41
Kostya Serebryany41740052016-01-12 02:36:59 +000042void PrintASCIIByte(uint8_t Byte) {
43 if (Byte == '\\')
44 Printf("\\\\");
45 else if (Byte == '"')
46 Printf("\\\"");
47 else if (Byte >= 32 && Byte < 127)
48 Printf("%c", Byte);
49 else
50 Printf("\\x%02x", Byte);
51}
52
53void PrintASCII(const uint8_t *Data, size_t Size, const char *PrintAfter) {
54 for (size_t i = 0; i < Size; i++)
55 PrintASCIIByte(Data[i]);
56 Printf("%s", PrintAfter);
57}
58
Aaron Ballmanef116982015-01-29 16:58:29 +000059void PrintASCII(const Unit &U, const char *PrintAfter) {
Kostya Serebryany476f0ce2016-01-16 03:53:32 +000060 PrintASCII(U.data(), U.size(), PrintAfter);
Aaron Ballmanef116982015-01-29 16:58:29 +000061}
62
Kostya Serebryany29bb6642016-09-21 22:42:17 +000063std::string Sha1ToString(const uint8_t Sha1[kSHA1NumBytes]) {
Kostya Serebryanya9a54802016-08-17 20:45:23 +000064 std::stringstream SS;
65 for (int i = 0; i < kSHA1NumBytes; i++)
66 SS << std::hex << std::setfill('0') << std::setw(2) << (unsigned)Sha1[i];
67 return SS.str();
68}
69
Kostya Serebryany96eab652015-05-14 22:41:49 +000070std::string Hash(const Unit &U) {
71 uint8_t Hash[kSHA1NumBytes];
72 ComputeSHA1(U.data(), U.size(), Hash);
Kostya Serebryanya9a54802016-08-17 20:45:23 +000073 return Sha1ToString(Hash);
Aaron Ballmanef116982015-01-29 16:58:29 +000074}
75
76static void AlarmHandler(int, siginfo_t *, void *) {
Kostya Serebryany52a788e2015-03-31 20:13:20 +000077 Fuzzer::StaticAlarmCallback();
Aaron Ballmanef116982015-01-29 16:58:29 +000078}
79
Kostya Serebryany228d5b12016-03-01 22:19:21 +000080static void CrashHandler(int, siginfo_t *, void *) {
81 Fuzzer::StaticCrashSignalCallback();
82}
83
84static void InterruptHandler(int, siginfo_t *, void *) {
85 Fuzzer::StaticInterruptCallback();
86}
87
88static void SetSigaction(int signum,
89 void (*callback)(int, siginfo_t *, void *)) {
90 struct sigaction sigact;
91 memset(&sigact, 0, sizeof(sigact));
92 sigact.sa_sigaction = callback;
Dmitry Vyukov2eed1212016-03-02 09:54:40 +000093 if (sigaction(signum, &sigact, 0)) {
94 Printf("libFuzzer: sigaction failed with %d\n", errno);
95 exit(1);
96 }
Kostya Serebryany228d5b12016-03-01 22:19:21 +000097}
98
Aaron Ballmanef116982015-01-29 16:58:29 +000099void SetTimer(int Seconds) {
100 struct itimerval T {{Seconds, 0}, {Seconds, 0}};
Dmitry Vyukov2eed1212016-03-02 09:54:40 +0000101 if (setitimer(ITIMER_REAL, &T, nullptr)) {
102 Printf("libFuzzer: setitimer failed with %d\n", errno);
103 exit(1);
104 }
Kostya Serebryany228d5b12016-03-01 22:19:21 +0000105 SetSigaction(SIGALRM, AlarmHandler);
Aaron Ballmanef116982015-01-29 16:58:29 +0000106}
107
Kostya Serebryany228d5b12016-03-01 22:19:21 +0000108void SetSigSegvHandler() { SetSigaction(SIGSEGV, CrashHandler); }
109void SetSigBusHandler() { SetSigaction(SIGBUS, CrashHandler); }
110void SetSigAbrtHandler() { SetSigaction(SIGABRT, CrashHandler); }
111void SetSigIllHandler() { SetSigaction(SIGILL, CrashHandler); }
112void SetSigFpeHandler() { SetSigaction(SIGFPE, CrashHandler); }
113void SetSigIntHandler() { SetSigaction(SIGINT, InterruptHandler); }
Kostya Serebryanyf389ae12016-03-24 21:03:58 +0000114void SetSigTermHandler() { SetSigaction(SIGTERM, InterruptHandler); }
Kostya Serebryany228d5b12016-03-01 22:19:21 +0000115
Kostya Serebryany9690fcf2015-05-12 18:51:57 +0000116int NumberOfCpuCores() {
Dan Liewe6ac1fd2016-05-20 01:30:36 +0000117 const char *CmdLine = nullptr;
118 if (LIBFUZZER_LINUX) {
119 CmdLine = "nproc";
120 } else if (LIBFUZZER_APPLE) {
121 CmdLine = "sysctl -n hw.ncpu";
122 } else {
123 assert(0 && "NumberOfCpuCores() is not implemented for your platform");
124 }
125
126 FILE *F = popen(CmdLine, "r");
127 int N = 1;
128 if (!F || fscanf(F, "%d", &N) != 1) {
129 Printf("WARNING: Failed to parse output of command \"%s\" in %s(). "
130 "Assuming CPU count of 1.\n",
131 CmdLine, __func__);
Dmitry Vyukov2eed1212016-03-02 09:54:40 +0000132 N = 1;
Dan Liewe6ac1fd2016-05-20 01:30:36 +0000133 }
134
135 if (pclose(F)) {
136 Printf("WARNING: Executing command \"%s\" failed in %s(). "
137 "Assuming CPU count of 1.\n",
138 CmdLine, __func__);
139 N = 1;
140 }
141 if (N < 1) {
142 Printf("WARNING: Reported CPU count (%d) from command \"%s\" was invalid "
143 "in %s(). Assuming CPU count of 1.\n",
144 N, CmdLine, __func__);
145 N = 1;
146 }
Kostya Serebryany9690fcf2015-05-12 18:51:57 +0000147 return N;
148}
149
Kostya Serebryany8a5bef02016-02-13 17:56:51 +0000150bool ToASCII(uint8_t *Data, size_t Size) {
Kostya Serebryanybc7c0ad2015-08-11 01:44:42 +0000151 bool Changed = false;
Kostya Serebryany8a5bef02016-02-13 17:56:51 +0000152 for (size_t i = 0; i < Size; i++) {
153 uint8_t &X = Data[i];
Kostya Serebryanybc7c0ad2015-08-11 01:44:42 +0000154 auto NewX = X;
155 NewX &= 127;
156 if (!isspace(NewX) && !isprint(NewX))
157 NewX = ' ';
158 Changed |= NewX != X;
159 X = NewX;
160 }
161 return Changed;
162}
163
Kostya Serebryanyf1f3f932016-05-26 20:03:02 +0000164bool IsASCII(const Unit &U) { return IsASCII(U.data(), U.size()); }
165
166bool IsASCII(const uint8_t *Data, size_t Size) {
167 for (size_t i = 0; i < Size; i++)
168 if (!(isprint(Data[i]) || isspace(Data[i]))) return false;
Kostya Serebryanya9346c22015-09-02 19:08:08 +0000169 return true;
170}
171
Kostya Serebryany9838b2b2015-09-03 20:23:46 +0000172bool ParseOneDictionaryEntry(const std::string &Str, Unit *U) {
173 U->clear();
174 if (Str.empty()) return false;
175 size_t L = 0, R = Str.size() - 1; // We are parsing the range [L,R].
176 // Skip spaces from both sides.
177 while (L < R && isspace(Str[L])) L++;
178 while (R > L && isspace(Str[R])) R--;
179 if (R - L < 2) return false;
180 // Check the closing "
181 if (Str[R] != '"') return false;
182 R--;
183 // Find the opening "
184 while (L < R && Str[L] != '"') L++;
185 if (L >= R) return false;
186 assert(Str[L] == '\"');
187 L++;
188 assert(L <= R);
189 for (size_t Pos = L; Pos <= R; Pos++) {
190 uint8_t V = (uint8_t)Str[Pos];
191 if (!isprint(V) && !isspace(V)) return false;
192 if (V =='\\') {
193 // Handle '\\'
194 if (Pos + 1 <= R && (Str[Pos + 1] == '\\' || Str[Pos + 1] == '"')) {
195 U->push_back(Str[Pos + 1]);
196 Pos++;
197 continue;
198 }
199 // Handle '\xAB'
200 if (Pos + 3 <= R && Str[Pos + 1] == 'x'
201 && isxdigit(Str[Pos + 2]) && isxdigit(Str[Pos + 3])) {
202 char Hex[] = "0xAA";
203 Hex[2] = Str[Pos + 2];
204 Hex[3] = Str[Pos + 3];
205 U->push_back(strtol(Hex, nullptr, 16));
206 Pos += 3;
207 continue;
208 }
209 return false; // Invalid escape.
210 } else {
211 // Any other character.
212 U->push_back(V);
213 }
214 }
215 return true;
216}
217
218bool ParseDictionaryFile(const std::string &Text, std::vector<Unit> *Units) {
219 if (Text.empty()) {
220 Printf("ParseDictionaryFile: file does not exist or is empty\n");
221 return false;
222 }
223 std::istringstream ISS(Text);
224 Units->clear();
225 Unit U;
226 int LineNo = 0;
227 std::string S;
228 while (std::getline(ISS, S, '\n')) {
229 LineNo++;
230 size_t Pos = 0;
231 while (Pos < S.size() && isspace(S[Pos])) Pos++; // Skip spaces.
232 if (Pos == S.size()) continue; // Empty line.
233 if (S[Pos] == '#') continue; // Comment line.
234 if (ParseOneDictionaryEntry(S, &U)) {
235 Units->push_back(U);
236 } else {
237 Printf("ParseDictionaryFile: error in line %d\n\t\t%s\n", LineNo,
238 S.c_str());
239 return false;
240 }
241 }
242 return true;
243}
244
Kostya Serebryany8b8f7a32016-05-06 23:38:07 +0000245void SleepSeconds(int Seconds) {
Kostya Serebryany3750c042016-09-19 20:32:34 +0000246 sleep(Seconds); // Use C API to avoid coverage from instrumented libc++.
Kostya Serebryany8b8f7a32016-05-06 23:38:07 +0000247}
Kostya Serebryanyd6edce92015-10-16 23:04:31 +0000248
Kostya Serebryany8b8f7a32016-05-06 23:38:07 +0000249int GetPid() { return getpid(); }
Kostya Serebryany9e48cda2015-12-04 22:29:39 +0000250
251std::string Base64(const Unit &U) {
252 static const char Table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
253 "abcdefghijklmnopqrstuvwxyz"
254 "0123456789+/";
255 std::string Res;
256 size_t i;
257 for (i = 0; i + 2 < U.size(); i += 3) {
258 uint32_t x = (U[i] << 16) + (U[i + 1] << 8) + U[i + 2];
259 Res += Table[(x >> 18) & 63];
260 Res += Table[(x >> 12) & 63];
261 Res += Table[(x >> 6) & 63];
262 Res += Table[x & 63];
263 }
264 if (i + 1 == U.size()) {
265 uint32_t x = (U[i] << 16);
266 Res += Table[(x >> 18) & 63];
267 Res += Table[(x >> 12) & 63];
268 Res += "==";
269 } else if (i + 2 == U.size()) {
270 uint32_t x = (U[i] << 16) + (U[i + 1] << 8);
271 Res += Table[(x >> 18) & 63];
272 Res += Table[(x >> 12) & 63];
273 Res += Table[(x >> 6) & 63];
274 Res += "=";
275 }
276 return Res;
277}
278
Kostya Serebryany66ff0752016-02-26 22:42:23 +0000279size_t GetPeakRSSMb() {
280 struct rusage usage;
281 if (getrusage(RUSAGE_SELF, &usage))
282 return 0;
Dan Liew11565442016-05-20 01:37:54 +0000283 if (LIBFUZZER_LINUX) {
284 // ru_maxrss is in KiB
285 return usage.ru_maxrss >> 10;
286 } else if (LIBFUZZER_APPLE) {
287 // ru_maxrss is in bytes
288 return usage.ru_maxrss >> 20;
289 }
290 assert(0 && "GetPeakRSSMb() is not implemented for your platform");
291 return 0;
Kostya Serebryany66ff0752016-02-26 22:42:23 +0000292}
293
Kostya Serebryany5ff481f2016-09-27 00:10:20 +0000294std::string DescribePC(const char *SymbolizedFMT, uintptr_t PC) {
295 if (!EF->__sanitizer_symbolize_pc) return "<can not symbolize>";
296 char PcDescr[1024];
297 EF->__sanitizer_symbolize_pc(reinterpret_cast<void*>(PC),
298 SymbolizedFMT, PcDescr, sizeof(PcDescr));
299 PcDescr[sizeof(PcDescr) - 1] = 0; // Just in case.
300 return PcDescr;
301}
302
Kostya Serebryanyb706b482016-09-18 21:47:08 +0000303void PrintPC(const char *SymbolizedFMT, const char *FallbackFMT, uintptr_t PC) {
Kostya Serebryany5ff481f2016-09-27 00:10:20 +0000304 if (EF->__sanitizer_symbolize_pc)
305 Printf("%s", DescribePC(SymbolizedFMT, PC).c_str());
306 else
Kostya Serebryanyb706b482016-09-18 21:47:08 +0000307 Printf(FallbackFMT, PC);
Kostya Serebryanyb706b482016-09-18 21:47:08 +0000308}
309
Kostya Serebryany95b1a432016-10-19 00:12:03 +0000310bool ExecuteCommandAndReadOutput(const std::string &Command, std::string *Out) {
311 FILE *Pipe = popen(Command.c_str(), "r");
312 if (!Pipe) return false;
313 char Buff[1024];
314 size_t N;
315 while ((N = fread(Buff, 1, sizeof(Buff), Pipe)) > 0)
316 Out->append(Buff, N);
317 return true;
318}
319
Aaron Ballmanef116982015-01-29 16:58:29 +0000320} // namespace fuzzer