Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmake: Add fuzzing facilities #43

Merged
merged 2 commits into from
Jan 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,26 @@ tristate_option(WITH_USDT

option(BUILD_TESTS "Build test_bitcoin executable." ON)
option(BUILD_BENCH "Build bench_bitcoin executable." ON)
cmake_dependent_option(BUILD_FUZZ_BINARY "Build fuzz binary." ON "NOT MSVC" OFF)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to other reviewers because I had to look up this syntax again. This does the obvious thing: If not msvc, provide the BUILD_FUZZ_BINARY option and set it to ON by default.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cmake_dependent_option(FUZZ "Build for fuzzing. Enabling this will disable all other targets and override BUILD_FUZZ_BINARY." OFF "NOT MSVC" OFF)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And this one means: If not msvc, provide the FUZZ option and set it to OFF by default.


if(FUZZ)
message(WARNING "FUZZ=ON will disable all other targets and force BUILD_FUZZ_BINARY=ON.")
set(BUILD_DAEMON OFF)
set(BUILD_CLI OFF)
set(BUILD_TX OFF)
set(BUILD_UTIL OFF)
set(BUILD_UTIL_CHAINSTATE OFF)
set(BUILD_SHARED_LIBS OFF)
set(BUILD_WALLET_TOOL OFF)
set(WITH_NATPMP OFF)
set(WITH_MINIUPNPC OFF)
set(WITH_ZMQ OFF)
set(BUILD_TESTS OFF)
set(BUILD_BENCH OFF)
set(BUILD_FUZZ_BINARY ON)
endif()

option(INSTALL_MAN "Install man pages." ON)

set(configure_warnings)
Expand Down Expand Up @@ -191,6 +211,40 @@ endif()
include(AddThreadsIfNeeded)
add_threads_if_needed()

add_library(sanitizing_interface INTERFACE)
target_link_libraries(core_interface INTERFACE sanitizing_interface)
if(SANITIZERS)
# First check if the compiler accepts flags. If an incompatible pair like
# -fsanitize=address,thread is used here, this check will fail. This will also
# fail if a bad argument is passed, e.g. -fsanitize=undfeined
try_append_cxx_flags("-fsanitize=${SANITIZERS}" TARGET sanitizing_interface
RESULT_VAR cxx_supports_sanitizers
)
if(NOT cxx_supports_sanitizers)
message(FATAL_ERROR "Compiler did not accept requested flags.")
endif()

# Some compilers (e.g. GCC) require additional libraries like libasan,
# libtsan, libubsan, etc. Make sure linking still works with the sanitize
# flag. This is a separate check so we can give a better error message when
# the sanitize flags are supported by the compiler but the actual sanitizer
# libs are missing.
try_append_linker_flag("-fsanitize=${SANITIZERS}" VAR SANITIZER_LDFLAGS
SOURCE "
#include <cstdint>
#include <cstddef>
extern \"C\" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { return 0; }
__attribute__((weak)) // allow for libFuzzer linking
int main() { return 0; }
"
RESULT_VAR linker_supports_sanitizers
)
if(NOT linker_supports_sanitizers)
message(FATAL_ERROR "Linker did not accept requested flags, you are missing required libraries.")
endif()
endif()
target_link_options(sanitizing_interface INTERFACE ${SANITIZER_LDFLAGS})

include(AddBoostIfNeeded)
add_boost_if_needed()

Expand Down Expand Up @@ -352,6 +406,7 @@ message(" USDT tracing ........................ ${WITH_USDT}")
message("Tests:")
message(" test_bitcoin ........................ ${BUILD_TESTS}")
message(" bench_bitcoin ....................... ${BUILD_BENCH}")
message(" fuzz binary ......................... ${BUILD_FUZZ_BINARY}")
message("")
if(CMAKE_CROSSCOMPILING)
set(cross_status "TRUE, for ${CMAKE_SYSTEM_NAME}, ${CMAKE_SYSTEM_PROCESSOR}")
Expand Down
4 changes: 4 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,10 @@ if(BUILD_TESTS)
add_subdirectory(test)
endif()

if(BUILD_FUZZ_BINARY)
add_subdirectory(test/fuzz)
endif()


install(TARGETS ${installable_targets}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
Expand Down
144 changes: 144 additions & 0 deletions src/test/fuzz/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# Copyright (c) 2023-present The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://opensource.org/license/mit/.

add_subdirectory(util)

add_executable(fuzz
addition_overflow.cpp
addrman.cpp
asmap.cpp
asmap_direct.cpp
autofile.cpp
banman.cpp
base_encode_decode.cpp
bech32.cpp
bip324.cpp
bitdeque.cpp
block.cpp
block_header.cpp
blockfilter.cpp
bloom_filter.cpp
buffered_file.cpp
chain.cpp
checkqueue.cpp
coins_view.cpp
coinscache_sim.cpp
connman.cpp
crypto.cpp
crypto_aes256.cpp
crypto_aes256cbc.cpp
crypto_chacha20.cpp
crypto_common.cpp
crypto_diff_fuzz_chacha20.cpp
crypto_hkdf_hmac_sha256_l32.cpp
crypto_poly1305.cpp
cuckoocache.cpp
decode_tx.cpp
descriptor_parse.cpp
deserialize.cpp
eval_script.cpp
fee_rate.cpp
fees.cpp
flatfile.cpp
float.cpp
golomb_rice.cpp
headerssync.cpp
hex.cpp
http_request.cpp
integer.cpp
key.cpp
key_io.cpp
kitchen_sink.cpp
load_external_block_file.cpp
locale.cpp
merkleblock.cpp
message.cpp
miniscript.cpp
minisketch.cpp
mini_miner.cpp
muhash.cpp
multiplication_overflow.cpp
net.cpp
net_permissions.cpp
netaddress.cpp
netbase_dns_lookup.cpp
node_eviction.cpp
p2p_transport_serialization.cpp
package_eval.cpp
parse_hd_keypath.cpp
parse_numbers.cpp
parse_script.cpp
parse_univalue.cpp
partially_downloaded_block.cpp
policy_estimator.cpp
policy_estimator_io.cpp
poolresource.cpp
pow.cpp
prevector.cpp
primitives_transaction.cpp
process_message.cpp
process_messages.cpp
protocol.cpp
psbt.cpp
random.cpp
rbf.cpp
rolling_bloom_filter.cpp
rpc.cpp
script.cpp
script_assets_test_minimizer.cpp
script_descriptor_cache.cpp
script_flags.cpp
script_format.cpp
script_interpreter.cpp
script_ops.cpp
script_sigcache.cpp
script_sign.cpp
scriptnum_ops.cpp
secp256k1_ec_seckey_import_export_der.cpp
secp256k1_ecdsa_signature_parse_der_lax.cpp
signature_checker.cpp
signet.cpp
socks5.cpp
span.cpp
spanparsing.cpp
string.cpp
strprintf.cpp
system.cpp
timedata.cpp
torcontrol.cpp
transaction.cpp
tx_in.cpp
tx_out.cpp
tx_pool.cpp
txorphan.cpp
txrequest.cpp
utxo_snapshot.cpp
utxo_total_supply.cpp
validation_load_mempool.cpp
versionbits.cpp
)
target_link_libraries(fuzz
hebasto marked this conversation as resolved.
Show resolved Hide resolved
core_interface
test_fuzz
bitcoin_cli
bitcoin_common
minisketch
leveldb
univalue
secp256k1
Boost::headers
libevent::libevent
)

if(ENABLE_WALLET)
target_sources(fuzz
PRIVATE
${CMAKE_SOURCE_DIR}/src/wallet/test/fuzz/coincontrol.cpp
${CMAKE_SOURCE_DIR}/src/wallet/test/fuzz/coinselection.cpp
${CMAKE_SOURCE_DIR}/src/wallet/test/fuzz/fees.cpp
${CMAKE_SOURCE_DIR}/src/wallet/test/fuzz/parse_iso8601.cpp
$<$<BOOL:${USE_SQLITE}>:${CMAKE_SOURCE_DIR}/src/wallet/test/fuzz/notifications.cpp>
)
target_link_libraries(fuzz bitcoin_wallet)
endif()
31 changes: 31 additions & 0 deletions src/test/fuzz/util/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Copyright (c) 2023-present The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://opensource.org/license/mit/.

add_library(test_fuzz STATIC EXCLUDE_FROM_ALL
descriptor.cpp
mempool.cpp
net.cpp
../fuzz.cpp
../util.cpp
)

target_link_libraries(test_fuzz
PRIVATE
core_interface
test_util
bitcoin_node
Boost::headers
)

include(CheckSourceCompilesAndLinks)
check_cxx_source_links_with_flags("${SANITIZER_LDFLAGS}" "
#include <cstdint>
#include <cstddef>
extern \"C\" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { return 0; }
// No main() function.
" BINARY_LINKS_WITHOUT_MAIN_FUNCTION
)
if(NOT BINARY_LINKS_WITHOUT_MAIN_FUNCTION)
target_compile_definitions(test_fuzz PRIVATE PROVIDE_FUZZ_MAIN_FUNCTION)
endif()
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ function(create_test_config)
set_configure_variable(BUILD_UTIL BUILD_BITCOIN_UTIL)
set_configure_variable(BUILD_WALLET_TOOL BUILD_BITCOIN_WALLET)
set_configure_variable(BUILD_DAEMON BUILD_BITCOIND_TRUE)
set_configure_variable(FUZZ ENABLE_FUZZ)
set_configure_variable(WITH_ZMQ ENABLE_ZMQ)
set_configure_variable(ENABLE_EXTERNAL_SIGNER ENABLE_EXTERNAL_SIGNER)
set_configure_variable(ENABLE_TRACING ENABLE_USDT_TRACEPOINTS)
Expand Down