1 //===- FuzzerUtil.cpp - Misc utils ----------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 //===----------------------------------------------------------------------===//
11 #include "FuzzerUtil.h"
13 #include "FuzzerInternal.h"
22 #include <sys/types.h>
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
);
34 void Print(const Unit
&v
, const char *PrintAfter
) {
35 PrintHexArray(v
.data(), v
.size(), PrintAfter
);
38 void PrintASCIIByte(uint8_t Byte
) {
43 else if (Byte
>= 32 && Byte
< 127)
46 Printf("\\%03o", Byte
);
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
);
55 void PrintASCII(const Unit
&U
, const char *PrintAfter
) {
56 PrintASCII(U
.data(), U
.size(), PrintAfter
);
59 bool ToASCII(uint8_t *Data
, size_t Size
) {
61 for (size_t i
= 0; i
< Size
; i
++) {
65 if (!isspace(NewX
) && !isprint(NewX
))
73 bool IsASCII(const Unit
&U
) { return IsASCII(U
.data(), U
.size()); }
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;
81 bool ParseOneDictionaryEntry(const std::string
&Str
, Unit
*U
) {
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;
93 while (L
< R
&& Str
[L
] != '"') L
++;
94 if (L
>= R
) return false;
95 assert(Str
[L
] == '\"');
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;
103 if (Pos
+ 1 <= R
&& (Str
[Pos
+ 1] == '\\' || Str
[Pos
+ 1] == '"')) {
104 U
->push_back(Str
[Pos
+ 1]);
109 if (Pos
+ 3 <= R
&& Str
[Pos
+ 1] == 'x'
110 && isxdigit(Str
[Pos
+ 2]) && isxdigit(Str
[Pos
+ 3])) {
112 Hex
[2] = Str
[Pos
+ 2];
113 Hex
[3] = Str
[Pos
+ 3];
114 U
->push_back(static_cast<uint8_t>(strtol(Hex
, nullptr, 16)));
118 return false; // Invalid escape.
120 // Any other character.
127 bool ParseDictionaryFile(const std::string
&Text
, std::vector
<Unit
> *Units
) {
129 Printf("ParseDictionaryFile: file does not exist or is empty\n");
132 std::istringstream
ISS(Text
);
137 while (std::getline(ISS
, S
, '\n')) {
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
)) {
146 Printf("ParseDictionaryFile: error in line %d\n\t\t%s\n", LineNo
,
154 // Code duplicated (and tested) in llvm/include/llvm/Support/Base64.h
155 std::string
Base64(const Unit
&U
) {
156 static const char Table
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
157 "abcdefghijklmnopqrstuvwxyz"
160 Buffer
.resize(((U
.size() + 2) / 3) * 4);
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];
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];
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];
187 static std::mutex SymbolizeMutex
;
189 std::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.
200 void PrintPC(const char *SymbolizedFMT
, const char *FallbackFMT
, uintptr_t PC
) {
201 if (EF
->__sanitizer_symbolize_pc
)
202 Printf("%s", DescribePC(SymbolizedFMT
, PC
).c_str());
204 Printf(FallbackFMT
, PC
);
207 void 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();
213 void 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);
219 unsigned NumberOfCpuCores() {
220 unsigned N
= std::thread::hardware_concurrency();
222 Printf("WARNING: std::thread::hardware_concurrency not well defined for "
223 "your platform. Assuming CPU count of 1.\n");
229 uint64_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
];
237 } // namespace fuzzer