Bitcoin: How can I efficiently trace code paths of Bitcoin core fuzz tests?

Tracing Code Paths for Fuzz Testing in Bitcoin Core

Fuzz testing, which involves intentionally introducing bugs or unexpected inputs into software systems to test their robustness and resilience, can be particularly difficult with complex codebases like Bitcoin Core. When it comes to tracing the source of function calls during fuzz testing, navigating the code can be frustrating, especially for developers who are not fully familiar with the underlying architecture.

Understanding Bitcoin Core’s Execution Model

Before we get into tracing code paths, let’s briefly understand how Bitcoin Core executes functions. The net_processing.cpp file is a critical component that performs various network-related tasks, such as packet processing, transaction verification, and executing consensus protocols. When executing this function, the CPU may execute a sequence of instructions that can be difficult to follow due to the nature of modern CPUs.

Frameworks for Fuzz Testing

To facilitate tracing code paths during fuzz testing, several frameworks have been developed:

  • AddressSanitizer

    : A highly optimized and efficient sanitizer for C/C++ that provides detailed information about memory accesses and function calls.

  • Valgrind: A memory debugging tool for detecting leaks, crashes, and other memory-related issues. It also includes a set of tools for fuzz testing.
  • GCC built-in strace command: This command allows you to execute system calls and inspect their arguments.

Using strace with fuzz testing

When using strace, it is important to start at the beginning of your fuzz testing function, as each call is traced separately. To do this, follow these steps:

  • Compile your Bitcoin core code into an object file (obj) and a shared library (libcore).
  • Use valgrind with gcc (or the equivalent for other compilers) to generate a binary containing the strace command:

gcc -std=c99 -g -Wall -Wextra --coverage -fsanitize=address obj/core.c -o core

valgrind --leak-check=full --show-leak-kinds=all --sysroot=/usr --follow-syms=core ./core

  • Run the generated binary with fuzz to start your fuzz test:

./core

Fuzz Test Example

To demonstrate how you can use strace to trace code paths, let’s create a simple example that generates a random number and checks if it matches an expected number. Value:

#include

uint32_t generateRandom(uint8_t* buffer) {

uint32_t generates;

do {

generates = rand();

} while (generates == 0);

// Introduce an error by changing the input buffer

*(buffer + 1) = 42;

return generates;

}

int main() {

const size_t bufSize = 10;

uint8_t buffer[bufSize];

uint32_t generates;

// Generate a random number, but introduce an error into the process

generates = generateRandom(buffer);

// Check if the expected value matches

assert(generated == 42 && memcmp(buffer, expected_value, bufSize) == 0);

return 0;

}

Tracing code paths

With this example and a basic understanding of how to use strace, you can follow these steps to trace code paths:

  • Compile the generateRandom.c file into an object file (obj) and a shared library (libcore).
  • Use valgrind with gcc (or equivalent) to generate a binary containing the strace command:

gcc -std=c99 -g -Wall -Wextra --coverage -fsanitize=address obj/core.c -o core

valgrind --leak-check=full --show-leak-kinds=all --sysroot=/usr --follow-syms=core ./core

  • Run the generated binary with fuzz to start your fuzz test:

./core

  • Use the strace command to check the function calls, focusing on the source of the error (i.e.

Ethereum Wallet Blockchain

Leave a Comment

Your email address will not be published. Required fields are marked *