238 lines · cpp
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-exception6//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 25namespace fuzzer {26 27void 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 34void Print(const Unit &v, const char *PrintAfter) {35 PrintHexArray(v.data(), v.size(), PrintAfter);36}37 38void 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 else46 Printf("\\%03o", Byte);47}48 49void 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 55void PrintASCII(const Unit &U, const char *PrintAfter) {56 PrintASCII(U.data(), U.size(), PrintAfter);57}58 59bool 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 73bool IsASCII(const Unit &U) { return IsASCII(U.data(), U.size()); }74 75bool 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 81bool 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(static_cast<uint8_t>(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 127bool ParseDictionaryFile(const std::string &Text, std::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// Code duplicated (and tested) in llvm/include/llvm/Support/Base64.h155std::string Base64(const Unit &U) {156 static const char Table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"157 "abcdefghijklmnopqrstuvwxyz"158 "0123456789+/";159 std::string Buffer;160 Buffer.resize(((U.size() + 2) / 3) * 4);161 162 size_t i = 0, j = 0;163 for (size_t n = U.size() / 3 * 3; i < n; i += 3, j += 4) {164 uint32_t x = ((unsigned char)U[i] << 16) | ((unsigned char)U[i + 1] << 8) |165 (unsigned char)U[i + 2];166 Buffer[j + 0] = Table[(x >> 18) & 63];167 Buffer[j + 1] = Table[(x >> 12) & 63];168 Buffer[j + 2] = Table[(x >> 6) & 63];169 Buffer[j + 3] = Table[x & 63];170 }171 if (i + 1 == U.size()) {172 uint32_t x = ((unsigned char)U[i] << 16);173 Buffer[j + 0] = Table[(x >> 18) & 63];174 Buffer[j + 1] = Table[(x >> 12) & 63];175 Buffer[j + 2] = '=';176 Buffer[j + 3] = '=';177 } else if (i + 2 == U.size()) {178 uint32_t x = ((unsigned char)U[i] << 16) | ((unsigned char)U[i + 1] << 8);179 Buffer[j + 0] = Table[(x >> 18) & 63];180 Buffer[j + 1] = Table[(x >> 12) & 63];181 Buffer[j + 2] = Table[(x >> 6) & 63];182 Buffer[j + 3] = '=';183 }184 return Buffer;185}186 187static std::mutex SymbolizeMutex;188 189std::string DescribePC(const char *SymbolizedFMT, uintptr_t PC) {190 std::unique_lock<std::mutex> l(SymbolizeMutex, std::try_to_lock);191 if (!EF->__sanitizer_symbolize_pc || !l.owns_lock())192 return "<can not symbolize>";193 char PcDescr[1024] = {};194 EF->__sanitizer_symbolize_pc(reinterpret_cast<void*>(PC),195 SymbolizedFMT, PcDescr, sizeof(PcDescr));196 PcDescr[sizeof(PcDescr) - 1] = 0; // Just in case.197 return PcDescr;198}199 200void PrintPC(const char *SymbolizedFMT, const char *FallbackFMT, uintptr_t PC) {201 if (EF->__sanitizer_symbolize_pc)202 Printf("%s", DescribePC(SymbolizedFMT, PC).c_str());203 else204 Printf(FallbackFMT, PC);205}206 207void PrintStackTrace() {208 std::unique_lock<std::mutex> l(SymbolizeMutex, std::try_to_lock);209 if (EF->__sanitizer_print_stack_trace && l.owns_lock())210 EF->__sanitizer_print_stack_trace();211}212 213void PrintMemoryProfile() {214 std::unique_lock<std::mutex> l(SymbolizeMutex, std::try_to_lock);215 if (EF->__sanitizer_print_memory_profile && l.owns_lock())216 EF->__sanitizer_print_memory_profile(95, 8);217}218 219unsigned NumberOfCpuCores() {220 unsigned N = std::thread::hardware_concurrency();221 if (!N) {222 Printf("WARNING: std::thread::hardware_concurrency not well defined for "223 "your platform. Assuming CPU count of 1.\n");224 N = 1;225 }226 return N;227}228 229uint64_t SimpleFastHash(const void *Data, size_t Size, uint64_t Initial) {230 uint64_t Res = Initial;231 const uint8_t *Bytes = static_cast<const uint8_t *>(Data);232 for (size_t i = 0; i < Size; i++)233 Res = Res * 11 + Bytes[i];234 return Res;235}236 237} // namespace fuzzer238