Skip to content

Commit 9dbcd68

Browse files
tests: Add FuzzedFileProvider which provides a FILE* interface to FuzzedDataProvider using fopencookie
1 parent 42fe6aa commit 9dbcd68

File tree

1 file changed

+119
-0
lines changed

1 file changed

+119
-0
lines changed

src/test/fuzz/util.h

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
#include <algorithm>
2929
#include <cstdint>
30+
#include <cstdio>
3031
#include <optional>
3132
#include <string>
3233
#include <vector>
@@ -264,4 +265,122 @@ void InitializeFuzzingContext(const std::string& chain_name = CBaseChainParams::
264265
static const BasicTestingSetup basic_testing_setup{chain_name, {"-nodebuglogfile"}};
265266
}
266267

268+
class FuzzedFileProvider
269+
{
270+
FuzzedDataProvider& m_fuzzed_data_provider;
271+
int64_t m_offset = 0;
272+
273+
public:
274+
FuzzedFileProvider(FuzzedDataProvider& fuzzed_data_provider) : m_fuzzed_data_provider{fuzzed_data_provider}
275+
{
276+
}
277+
278+
FILE* open()
279+
{
280+
if (m_fuzzed_data_provider.ConsumeBool()) {
281+
return nullptr;
282+
}
283+
std::string mode;
284+
switch (m_fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 5)) {
285+
case 0: {
286+
mode = "r";
287+
break;
288+
}
289+
case 1: {
290+
mode = "r+";
291+
break;
292+
}
293+
case 2: {
294+
mode = "w";
295+
break;
296+
}
297+
case 3: {
298+
mode = "w+";
299+
break;
300+
}
301+
case 4: {
302+
mode = "a";
303+
break;
304+
}
305+
case 5: {
306+
mode = "a+";
307+
break;
308+
}
309+
}
310+
#ifdef _GNU_SOURCE
311+
const cookie_io_functions_t io_hooks = {
312+
FuzzedFileProvider::read,
313+
FuzzedFileProvider::write,
314+
FuzzedFileProvider::seek,
315+
FuzzedFileProvider::close,
316+
};
317+
return fopencookie(this, mode.c_str(), io_hooks);
318+
#else
319+
(void)mode;
320+
return nullptr;
321+
#endif
322+
}
323+
324+
static ssize_t read(void* cookie, char* buf, size_t size)
325+
{
326+
FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
327+
if (buf == nullptr || size == 0 || fuzzed_file->m_fuzzed_data_provider.ConsumeBool()) {
328+
return fuzzed_file->m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
329+
}
330+
const std::vector<uint8_t> random_bytes = fuzzed_file->m_fuzzed_data_provider.ConsumeBytes<uint8_t>(size);
331+
if (random_bytes.empty()) {
332+
return 0;
333+
}
334+
std::memcpy(buf, random_bytes.data(), random_bytes.size());
335+
if (AdditionOverflow((uint64_t)fuzzed_file->m_offset, random_bytes.size())) {
336+
return fuzzed_file->m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
337+
}
338+
fuzzed_file->m_offset += random_bytes.size();
339+
return random_bytes.size();
340+
}
341+
342+
static ssize_t write(void* cookie, const char* buf, size_t size)
343+
{
344+
FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
345+
const ssize_t n = fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<ssize_t>(0, size);
346+
if (AdditionOverflow(fuzzed_file->m_offset, n)) {
347+
return fuzzed_file->m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
348+
}
349+
fuzzed_file->m_offset += n;
350+
return n;
351+
}
352+
353+
static int seek(void* cookie, int64_t* offset, int whence)
354+
{
355+
assert(whence == SEEK_SET || whence == SEEK_CUR); // SEEK_END not implemented yet.
356+
FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
357+
int64_t new_offset = 0;
358+
if (whence == SEEK_SET) {
359+
new_offset = *offset;
360+
} else if (whence == SEEK_CUR) {
361+
if (AdditionOverflow(fuzzed_file->m_offset, *offset)) {
362+
return -1;
363+
}
364+
new_offset = fuzzed_file->m_offset + *offset;
365+
}
366+
if (new_offset < 0) {
367+
return -1;
368+
}
369+
fuzzed_file->m_offset = new_offset;
370+
*offset = new_offset;
371+
return fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<int>(-1, 0);
372+
}
373+
374+
static int close(void* cookie)
375+
{
376+
FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
377+
return fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<int>(-1, 0);
378+
}
379+
};
380+
381+
NODISCARD inline FuzzedFileProvider ConsumeFile(FuzzedDataProvider& fuzzed_data_provider) noexcept
382+
{
383+
return {fuzzed_data_provider};
384+
}
385+
267386
#endif // BITCOIN_TEST_FUZZ_UTIL_H

0 commit comments

Comments
 (0)