Skip to content

Commit 0eea1df

Browse files
author
MarcoFalke
committed
Merge bitcoin#22445: fuzz: Move implementations of non-template fuzz helpers from util.h to util.cpp
a2aca20 Move implementations of non-template fuzz helpers (Sriram) Pull request description: There are 78 cpp files that include `util.h` (`grep -iIr "#include <test/fuzz/util.h>" src/test/fuzz | wc -l`). Modifying the implementation of a fuzz helper in `src/test/fuzz/util.h` will cause all fuzz tests to be recompiled. Keeping the declarations of these non-template fuzz helpers in `util.h` and moving their implementations to `util.cpp` will skip the redundant recompilation of all the fuzz tests, and builds these helpers only once in `util.cpp`. Functions moved from `util.h` to `util.cpp`: - `ConsumeTxMemPoolEntry` - `ContainsSpentInput` - `ConsumeNetAddr` - Methods of `FuzzedFileProvider::(open, read, write, seek, close)` ACKs for top commit: MarcoFalke: review ACK a2aca20 🍂 Tree-SHA512: e7037ebb86d0fc56048e4f3d8733eefc21da11683b09d2b22926bda410719628d89c52ddd9b4c18aa243607a66fdb4d13a63e62ca010e66b3ec9174fd18107f0
2 parents 5341c3b + a2aca20 commit 0eea1df

File tree

2 files changed

+163
-147
lines changed

2 files changed

+163
-147
lines changed

src/test/fuzz/util.cpp

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,3 +343,158 @@ CTxDestination ConsumeTxDestination(FuzzedDataProvider& fuzzed_data_provider) no
343343
Assert(call_size == std::variant_size_v<CTxDestination>);
344344
return tx_destination;
345345
}
346+
347+
CTxMemPoolEntry ConsumeTxMemPoolEntry(FuzzedDataProvider& fuzzed_data_provider, const CTransaction& tx) noexcept
348+
{
349+
// Avoid:
350+
// policy/feerate.cpp:28:34: runtime error: signed integer overflow: 34873208148477500 * 1000 cannot be represented in type 'long'
351+
//
352+
// Reproduce using CFeeRate(348732081484775, 10).GetFeePerK()
353+
const CAmount fee = std::min<CAmount>(ConsumeMoney(fuzzed_data_provider), std::numeric_limits<CAmount>::max() / static_cast<CAmount>(100000));
354+
assert(MoneyRange(fee));
355+
const int64_t time = fuzzed_data_provider.ConsumeIntegral<int64_t>();
356+
const unsigned int entry_height = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
357+
const bool spends_coinbase = fuzzed_data_provider.ConsumeBool();
358+
const unsigned int sig_op_cost = fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(0, MAX_BLOCK_SIGOPS_COST);
359+
return CTxMemPoolEntry{MakeTransactionRef(tx), fee, time, entry_height, spends_coinbase, sig_op_cost, {}};
360+
}
361+
362+
bool ContainsSpentInput(const CTransaction& tx, const CCoinsViewCache& inputs) noexcept
363+
{
364+
for (const CTxIn& tx_in : tx.vin) {
365+
const Coin& coin = inputs.AccessCoin(tx_in.prevout);
366+
if (coin.IsSpent()) {
367+
return true;
368+
}
369+
}
370+
return false;
371+
}
372+
373+
CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept
374+
{
375+
const Network network = fuzzed_data_provider.PickValueInArray({Network::NET_IPV4, Network::NET_IPV6, Network::NET_INTERNAL, Network::NET_ONION});
376+
CNetAddr net_addr;
377+
if (network == Network::NET_IPV4) {
378+
in_addr v4_addr = {};
379+
v4_addr.s_addr = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
380+
net_addr = CNetAddr{v4_addr};
381+
} else if (network == Network::NET_IPV6) {
382+
if (fuzzed_data_provider.remaining_bytes() >= 16) {
383+
in6_addr v6_addr = {};
384+
memcpy(v6_addr.s6_addr, fuzzed_data_provider.ConsumeBytes<uint8_t>(16).data(), 16);
385+
net_addr = CNetAddr{v6_addr, fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
386+
}
387+
} else if (network == Network::NET_INTERNAL) {
388+
net_addr.SetInternal(fuzzed_data_provider.ConsumeBytesAsString(32));
389+
} else if (network == Network::NET_ONION) {
390+
net_addr.SetSpecial(fuzzed_data_provider.ConsumeBytesAsString(32));
391+
}
392+
return net_addr;
393+
}
394+
395+
FILE* FuzzedFileProvider::open()
396+
{
397+
SetFuzzedErrNo(m_fuzzed_data_provider);
398+
if (m_fuzzed_data_provider.ConsumeBool()) {
399+
return nullptr;
400+
}
401+
std::string mode;
402+
CallOneOf(
403+
m_fuzzed_data_provider,
404+
[&] {
405+
mode = "r";
406+
},
407+
[&] {
408+
mode = "r+";
409+
},
410+
[&] {
411+
mode = "w";
412+
},
413+
[&] {
414+
mode = "w+";
415+
},
416+
[&] {
417+
mode = "a";
418+
},
419+
[&] {
420+
mode = "a+";
421+
});
422+
#if defined _GNU_SOURCE && !defined __ANDROID__
423+
const cookie_io_functions_t io_hooks = {
424+
FuzzedFileProvider::read,
425+
FuzzedFileProvider::write,
426+
FuzzedFileProvider::seek,
427+
FuzzedFileProvider::close,
428+
};
429+
return fopencookie(this, mode.c_str(), io_hooks);
430+
#else
431+
(void)mode;
432+
return nullptr;
433+
#endif
434+
}
435+
436+
ssize_t FuzzedFileProvider::read(void* cookie, char* buf, size_t size)
437+
{
438+
FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
439+
SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider);
440+
if (buf == nullptr || size == 0 || fuzzed_file->m_fuzzed_data_provider.ConsumeBool()) {
441+
return fuzzed_file->m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
442+
}
443+
const std::vector<uint8_t> random_bytes = fuzzed_file->m_fuzzed_data_provider.ConsumeBytes<uint8_t>(size);
444+
if (random_bytes.empty()) {
445+
return 0;
446+
}
447+
std::memcpy(buf, random_bytes.data(), random_bytes.size());
448+
if (AdditionOverflow(fuzzed_file->m_offset, (int64_t)random_bytes.size())) {
449+
return fuzzed_file->m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
450+
}
451+
fuzzed_file->m_offset += random_bytes.size();
452+
return random_bytes.size();
453+
}
454+
455+
ssize_t FuzzedFileProvider::write(void* cookie, const char* buf, size_t size)
456+
{
457+
FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
458+
SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider);
459+
const ssize_t n = fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<ssize_t>(0, size);
460+
if (AdditionOverflow(fuzzed_file->m_offset, (int64_t)n)) {
461+
return fuzzed_file->m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
462+
}
463+
fuzzed_file->m_offset += n;
464+
return n;
465+
}
466+
467+
int FuzzedFileProvider::seek(void* cookie, int64_t* offset, int whence)
468+
{
469+
assert(whence == SEEK_SET || whence == SEEK_CUR || whence == SEEK_END);
470+
FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
471+
SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider);
472+
int64_t new_offset = 0;
473+
if (whence == SEEK_SET) {
474+
new_offset = *offset;
475+
} else if (whence == SEEK_CUR) {
476+
if (AdditionOverflow(fuzzed_file->m_offset, *offset)) {
477+
return -1;
478+
}
479+
new_offset = fuzzed_file->m_offset + *offset;
480+
} else if (whence == SEEK_END) {
481+
const int64_t n = fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, 4096);
482+
if (AdditionOverflow(n, *offset)) {
483+
return -1;
484+
}
485+
new_offset = n + *offset;
486+
}
487+
if (new_offset < 0) {
488+
return -1;
489+
}
490+
fuzzed_file->m_offset = new_offset;
491+
*offset = new_offset;
492+
return fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<int>(-1, 0);
493+
}
494+
495+
int FuzzedFileProvider::close(void* cookie)
496+
{
497+
FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
498+
SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider);
499+
return fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<int>(-1, 0);
500+
}

src/test/fuzz/util.h

Lines changed: 8 additions & 147 deletions
Original file line numberDiff line numberDiff line change
@@ -164,20 +164,7 @@ template <typename WeakEnumType, size_t size>
164164
return UintToArith256(ConsumeUInt256(fuzzed_data_provider));
165165
}
166166

167-
[[nodiscard]] inline CTxMemPoolEntry ConsumeTxMemPoolEntry(FuzzedDataProvider& fuzzed_data_provider, const CTransaction& tx) noexcept
168-
{
169-
// Avoid:
170-
// policy/feerate.cpp:28:34: runtime error: signed integer overflow: 34873208148477500 * 1000 cannot be represented in type 'long'
171-
//
172-
// Reproduce using CFeeRate(348732081484775, 10).GetFeePerK()
173-
const CAmount fee = std::min<CAmount>(ConsumeMoney(fuzzed_data_provider), std::numeric_limits<CAmount>::max() / static_cast<CAmount>(100000));
174-
assert(MoneyRange(fee));
175-
const int64_t time = fuzzed_data_provider.ConsumeIntegral<int64_t>();
176-
const unsigned int entry_height = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
177-
const bool spends_coinbase = fuzzed_data_provider.ConsumeBool();
178-
const unsigned int sig_op_cost = fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(0, MAX_BLOCK_SIGOPS_COST);
179-
return CTxMemPoolEntry{MakeTransactionRef(tx), fee, time, entry_height, spends_coinbase, sig_op_cost, {}};
180-
}
167+
[[nodiscard]] CTxMemPoolEntry ConsumeTxMemPoolEntry(FuzzedDataProvider& fuzzed_data_provider, const CTransaction& tx) noexcept;
181168

182169
[[nodiscard]] CTxDestination ConsumeTxDestination(FuzzedDataProvider& fuzzed_data_provider) noexcept;
183170

@@ -215,16 +202,7 @@ template <class T>
215202
return std::numeric_limits<T>::max() - i < j;
216203
}
217204

218-
[[nodiscard]] inline bool ContainsSpentInput(const CTransaction& tx, const CCoinsViewCache& inputs) noexcept
219-
{
220-
for (const CTxIn& tx_in : tx.vin) {
221-
const Coin& coin = inputs.AccessCoin(tx_in.prevout);
222-
if (coin.IsSpent()) {
223-
return true;
224-
}
225-
}
226-
return false;
227-
}
205+
[[nodiscard]] bool ContainsSpentInput(const CTransaction& tx, const CCoinsViewCache& inputs) noexcept;
228206

229207
/**
230208
* Sets errno to a value selected from the given std::array `errnos`.
@@ -259,27 +237,7 @@ inline void SetFuzzedErrNo(FuzzedDataProvider& fuzzed_data_provider) noexcept
259237
return result;
260238
}
261239

262-
inline CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept
263-
{
264-
const Network network = fuzzed_data_provider.PickValueInArray({Network::NET_IPV4, Network::NET_IPV6, Network::NET_INTERNAL, Network::NET_ONION});
265-
CNetAddr net_addr;
266-
if (network == Network::NET_IPV4) {
267-
in_addr v4_addr = {};
268-
v4_addr.s_addr = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
269-
net_addr = CNetAddr{v4_addr};
270-
} else if (network == Network::NET_IPV6) {
271-
if (fuzzed_data_provider.remaining_bytes() >= 16) {
272-
in6_addr v6_addr = {};
273-
memcpy(v6_addr.s6_addr, fuzzed_data_provider.ConsumeBytes<uint8_t>(16).data(), 16);
274-
net_addr = CNetAddr{v6_addr, fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
275-
}
276-
} else if (network == Network::NET_INTERNAL) {
277-
net_addr.SetInternal(fuzzed_data_provider.ConsumeBytesAsString(32));
278-
} else if (network == Network::NET_ONION) {
279-
net_addr.SetSpecial(fuzzed_data_provider.ConsumeBytesAsString(32));
280-
}
281-
return net_addr;
282-
}
240+
CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept;
283241

284242
inline CSubNet ConsumeSubNet(FuzzedDataProvider& fuzzed_data_provider) noexcept
285243
{
@@ -329,112 +287,15 @@ class FuzzedFileProvider
329287
{
330288
}
331289

332-
FILE* open()
333-
{
334-
SetFuzzedErrNo(m_fuzzed_data_provider);
335-
if (m_fuzzed_data_provider.ConsumeBool()) {
336-
return nullptr;
337-
}
338-
std::string mode;
339-
CallOneOf(
340-
m_fuzzed_data_provider,
341-
[&] {
342-
mode = "r";
343-
},
344-
[&] {
345-
mode = "r+";
346-
},
347-
[&] {
348-
mode = "w";
349-
},
350-
[&] {
351-
mode = "w+";
352-
},
353-
[&] {
354-
mode = "a";
355-
},
356-
[&] {
357-
mode = "a+";
358-
});
359-
#if defined _GNU_SOURCE && !defined __ANDROID__
360-
const cookie_io_functions_t io_hooks = {
361-
FuzzedFileProvider::read,
362-
FuzzedFileProvider::write,
363-
FuzzedFileProvider::seek,
364-
FuzzedFileProvider::close,
365-
};
366-
return fopencookie(this, mode.c_str(), io_hooks);
367-
#else
368-
(void)mode;
369-
return nullptr;
370-
#endif
371-
}
290+
FILE* open();
372291

373-
static ssize_t read(void* cookie, char* buf, size_t size)
374-
{
375-
FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
376-
SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider);
377-
if (buf == nullptr || size == 0 || fuzzed_file->m_fuzzed_data_provider.ConsumeBool()) {
378-
return fuzzed_file->m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
379-
}
380-
const std::vector<uint8_t> random_bytes = fuzzed_file->m_fuzzed_data_provider.ConsumeBytes<uint8_t>(size);
381-
if (random_bytes.empty()) {
382-
return 0;
383-
}
384-
std::memcpy(buf, random_bytes.data(), random_bytes.size());
385-
if (AdditionOverflow(fuzzed_file->m_offset, (int64_t)random_bytes.size())) {
386-
return fuzzed_file->m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
387-
}
388-
fuzzed_file->m_offset += random_bytes.size();
389-
return random_bytes.size();
390-
}
292+
static ssize_t read(void* cookie, char* buf, size_t size);
391293

392-
static ssize_t write(void* cookie, const char* buf, size_t size)
393-
{
394-
FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
395-
SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider);
396-
const ssize_t n = fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<ssize_t>(0, size);
397-
if (AdditionOverflow(fuzzed_file->m_offset, (int64_t)n)) {
398-
return fuzzed_file->m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
399-
}
400-
fuzzed_file->m_offset += n;
401-
return n;
402-
}
294+
static ssize_t write(void* cookie, const char* buf, size_t size);
403295

404-
static int seek(void* cookie, int64_t* offset, int whence)
405-
{
406-
assert(whence == SEEK_SET || whence == SEEK_CUR || whence == SEEK_END);
407-
FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
408-
SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider);
409-
int64_t new_offset = 0;
410-
if (whence == SEEK_SET) {
411-
new_offset = *offset;
412-
} else if (whence == SEEK_CUR) {
413-
if (AdditionOverflow(fuzzed_file->m_offset, *offset)) {
414-
return -1;
415-
}
416-
new_offset = fuzzed_file->m_offset + *offset;
417-
} else if (whence == SEEK_END) {
418-
const int64_t n = fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, 4096);
419-
if (AdditionOverflow(n, *offset)) {
420-
return -1;
421-
}
422-
new_offset = n + *offset;
423-
}
424-
if (new_offset < 0) {
425-
return -1;
426-
}
427-
fuzzed_file->m_offset = new_offset;
428-
*offset = new_offset;
429-
return fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<int>(-1, 0);
430-
}
296+
static int seek(void* cookie, int64_t* offset, int whence);
431297

432-
static int close(void* cookie)
433-
{
434-
FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
435-
SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider);
436-
return fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<int>(-1, 0);
437-
}
298+
static int close(void* cookie);
438299
};
439300

440301
[[nodiscard]] inline FuzzedFileProvider ConsumeFile(FuzzedDataProvider& fuzzed_data_provider) noexcept

0 commit comments

Comments
 (0)