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