1 //===- FuzzerUtil.cpp - Misc utils ----------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // Misc utils. 9 //===----------------------------------------------------------------------===// 10 11 #include "FuzzerUtil.h" 12 #include "FuzzerIO.h" 13 #include "FuzzerInternal.h" 14 #include <cassert> 15 #include <chrono> 16 #include <cstring> 17 #include <errno.h> 18 #include <mutex> 19 #include <signal.h> 20 #include <sstream> 21 #include <stdio.h> 22 #include <sys/types.h> 23 #include <thread> 24 25 namespace fuzzer { 26 27 void PrintHexArray(const uint8_t *Data, size_t Size, 28 const char *PrintAfter) { 29 for (size_t i = 0; i < Size; i++) 30 Printf("0x%x,", (unsigned)Data[i]); 31 Printf("%s", PrintAfter); 32 } 33 34 void Print(const Unit &v, const char *PrintAfter) { 35 PrintHexArray(v.data(), v.size(), PrintAfter); 36 } 37 38 void PrintASCIIByte(uint8_t Byte) { 39 if (Byte == '\\') 40 Printf("\\\\"); 41 else if (Byte == '"') 42 Printf("\\\""); 43 else if (Byte >= 32 && Byte < 127) 44 Printf("%c", Byte); 45 else 46 Printf("\\x%02x", Byte); 47 } 48 49 void PrintASCII(const uint8_t *Data, size_t Size, const char *PrintAfter) { 50 for (size_t i = 0; i < Size; i++) 51 PrintASCIIByte(Data[i]); 52 Printf("%s", PrintAfter); 53 } 54 55 void PrintASCII(const Unit &U, const char *PrintAfter) { 56 PrintASCII(U.data(), U.size(), PrintAfter); 57 } 58 59 bool ToASCII(uint8_t *Data, size_t Size) { 60 bool Changed = false; 61 for (size_t i = 0; i < Size; i++) { 62 uint8_t &X = Data[i]; 63 auto NewX = X; 64 NewX &= 127; 65 if (!isspace(NewX) && !isprint(NewX)) 66 NewX = ' '; 67 Changed |= NewX != X; 68 X = NewX; 69 } 70 return Changed; 71 } 72 73 bool IsASCII(const Unit &U) { return IsASCII(U.data(), U.size()); } 74 75 bool IsASCII(const uint8_t *Data, size_t Size) { 76 for (size_t i = 0; i < Size; i++) 77 if (!(isprint(Data[i]) || isspace(Data[i]))) return false; 78 return true; 79 } 80 81 bool ParseOneDictionaryEntry(const std::string &Str, Unit *U) { 82 U->clear(); 83 if (Str.empty()) return false; 84 size_t L = 0, R = Str.size() - 1; // We are parsing the range [L,R]. 85 // Skip spaces from both sides. 86 while (L < R && isspace(Str[L])) L++; 87 while (R > L && isspace(Str[R])) R--; 88 if (R - L < 2) return false; 89 // Check the closing " 90 if (Str[R] != '"') return false; 91 R--; 92 // Find the opening " 93 while (L < R && Str[L] != '"') L++; 94 if (L >= R) return false; 95 assert(Str[L] == '\"'); 96 L++; 97 assert(L <= R); 98 for (size_t Pos = L; Pos <= R; Pos++) { 99 uint8_t V = (uint8_t)Str[Pos]; 100 if (!isprint(V) && !isspace(V)) return false; 101 if (V =='\\') { 102 // Handle '\\' 103 if (Pos + 1 <= R && (Str[Pos + 1] == '\\' || Str[Pos + 1] == '"')) { 104 U->push_back(Str[Pos + 1]); 105 Pos++; 106 continue; 107 } 108 // Handle '\xAB' 109 if (Pos + 3 <= R && Str[Pos + 1] == 'x' 110 && isxdigit(Str[Pos + 2]) && isxdigit(Str[Pos + 3])) { 111 char Hex[] = "0xAA"; 112 Hex[2] = Str[Pos + 2]; 113 Hex[3] = Str[Pos + 3]; 114 U->push_back(strtol(Hex, nullptr, 16)); 115 Pos += 3; 116 continue; 117 } 118 return false; // Invalid escape. 119 } else { 120 // Any other character. 121 U->push_back(V); 122 } 123 } 124 return true; 125 } 126 127 bool ParseDictionaryFile(const std::string &Text, Vector<Unit> *Units) { 128 if (Text.empty()) { 129 Printf("ParseDictionaryFile: file does not exist or is empty\n"); 130 return false; 131 } 132 std::istringstream ISS(Text); 133 Units->clear(); 134 Unit U; 135 int LineNo = 0; 136 std::string S; 137 while (std::getline(ISS, S, '\n')) { 138 LineNo++; 139 size_t Pos = 0; 140 while (Pos < S.size() && isspace(S[Pos])) Pos++; // Skip spaces. 141 if (Pos == S.size()) continue; // Empty line. 142 if (S[Pos] == '#') continue; // Comment line. 143 if (ParseOneDictionaryEntry(S, &U)) { 144 Units->push_back(U); 145 } else { 146 Printf("ParseDictionaryFile: error in line %d\n\t\t%s\n", LineNo, 147 S.c_str()); 148 return false; 149 } 150 } 151 return true; 152 } 153 154 std::string Base64(const Unit &U) { 155 static const char Table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 156 "abcdefghijklmnopqrstuvwxyz" 157 "0123456789+/"; 158 std::string Res; 159 size_t i; 160 for (i = 0; i + 2 < U.size(); i += 3) { 161 uint32_t x = (U[i] << 16) + (U[i + 1] << 8) + U[i + 2]; 162 Res += Table[(x >> 18) & 63]; 163 Res += Table[(x >> 12) & 63]; 164 Res += Table[(x >> 6) & 63]; 165 Res += Table[x & 63]; 166 } 167 if (i + 1 == U.size()) { 168 uint32_t x = (U[i] << 16); 169 Res += Table[(x >> 18) & 63]; 170 Res += Table[(x >> 12) & 63]; 171 Res += "=="; 172 } else if (i + 2 == U.size()) { 173 uint32_t x = (U[i] << 16) + (U[i + 1] << 8); 174 Res += Table[(x >> 18) & 63]; 175 Res += Table[(x >> 12) & 63]; 176 Res += Table[(x >> 6) & 63]; 177 Res += "="; 178 } 179 return Res; 180 } 181 182 static std::mutex SymbolizeMutex; 183 184 std::string DescribePC(const char *SymbolizedFMT, uintptr_t PC) { 185 std::unique_lock<std::mutex> l(SymbolizeMutex, std::try_to_lock); 186 if (!EF->__sanitizer_symbolize_pc || !l.owns_lock()) 187 return "<can not symbolize>"; 188 char PcDescr[1024] = {}; 189 EF->__sanitizer_symbolize_pc(reinterpret_cast<void*>(PC), 190 SymbolizedFMT, PcDescr, sizeof(PcDescr)); 191 PcDescr[sizeof(PcDescr) - 1] = 0; // Just in case. 192 return PcDescr; 193 } 194 195 void PrintPC(const char *SymbolizedFMT, const char *FallbackFMT, uintptr_t PC) { 196 if (EF->__sanitizer_symbolize_pc) 197 Printf("%s", DescribePC(SymbolizedFMT, PC).c_str()); 198 else 199 Printf(FallbackFMT, PC); 200 } 201 202 void PrintStackTrace() { 203 std::unique_lock<std::mutex> l(SymbolizeMutex, std::try_to_lock); 204 if (EF->__sanitizer_print_stack_trace && l.owns_lock()) 205 EF->__sanitizer_print_stack_trace(); 206 } 207 208 void PrintMemoryProfile() { 209 std::unique_lock<std::mutex> l(SymbolizeMutex, std::try_to_lock); 210 if (EF->__sanitizer_print_memory_profile && l.owns_lock()) 211 EF->__sanitizer_print_memory_profile(95, 8); 212 } 213 214 unsigned NumberOfCpuCores() { 215 unsigned N = std::thread::hardware_concurrency(); 216 if (!N) { 217 Printf("WARNING: std::thread::hardware_concurrency not well defined for " 218 "your platform. Assuming CPU count of 1.\n"); 219 N = 1; 220 } 221 return N; 222 } 223 224 size_t SimpleFastHash(const uint8_t *Data, size_t Size) { 225 size_t Res = 0; 226 for (size_t i = 0; i < Size; i++) 227 Res = Res * 11 + Data[i]; 228 return Res; 229 } 230 231 } // namespace fuzzer 232