What changed, and why it matters
This commit is a maintenance change that switches the project's fuzz testing framework from Honggfuzz to libfuzzer (cargo-fuzz). It updates build files, CI configuration, documentation, and fuzz target source files to use the new framework. There is no change to the actual Bitcoin library code that end users or applications depend on, and no security vulnerability is introduced or fixed.
No security action required. This is a testing-infrastructure refactor. Reviewers may optionally verify that CI fuzz jobs still execute all targets and that the new libfuzzer build works across supported architectures.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit migrates the rust-bitcoin fuzz harness from honggfuzz-rs to libfuzzer-sys/cargo-fuzz. Changes include: replacing the honggfuzz dependency with libfuzzer-sys in Cargo.lock and fuzz/Cargo.toml; rewriting all fuzz target entry points to use libfuzzer_sys::fuzz_target! instead of honggfuzz::fuzz!; removing the per-target duplicate_crash test modules; updating helper scripts (fuzz.sh, cycle.sh, fuzz-util.sh, generate-files.sh) and README to reference cargo-fuzz; adding a custom Cross Docker image for s390x/aarch64 with GCC 13 to satisfy libfuzzer-sys C++17 requirements; and moving fuzz into a nested workspace. No runtime library code is modified.
Changed components
fuzz/Cargo.tomlfuzz/fuzz_targets/*fuzz/fuzz.shfuzz/cycle.shfuzz/fuzz-util.shfuzz/generate-files.shfuzz/README.md.github/workflows/cron-daily-fuzz.yml.github/workflows/rust.yml.github/docker/Dockerfile.crossCross.tomlCargo-minimal.lockCargo-recent.lockInspect captured patch +603 / −1206
diff --git a/.github/docker/Dockerfile.cross b/.github/docker/Dockerfile.cross
new file mode 100644
index 00000000..f2e5a746
--- /dev/null
+++ b/.github/docker/Dockerfile.cross
@@ -0,0 +1,53 @@
+FROM ubuntu:24.04
+
+RUN apt-get update && \
+ apt-get install -y --no-install-recommends \
+ gcc g++ \
+ gcc-14-s390x-linux-gnu \
+ g++-14-s390x-linux-gnu \
+ libc6-dev-s390x-cross \
+ libstdc++-14-dev-s390x-cross \
+ gcc-14-aarch64-linux-gnu \
+ g++-14-aarch64-linux-gnu \
+ libc6-dev-arm64-cross \
+ libstdc++-14-dev-arm64-cross \
+ qemu-user-static \
+ binfmt-support \
+ curl \
+ ca-certificates && \
+ rm -rf /var/lib/apt/lists/*
+
+RUN update-alternatives --install /usr/bin/s390x-linux-gnu-gcc s390x-linux-gnu-gcc /usr/bin/s390x-linux-gnu-gcc-14 100 && \
+ update-alternatives --install /usr/bin/s390x-linux-gnu-g++ s390x-linux-gnu-g++ /usr/bin/s390x-linux-gnu-g++-14 100
+
+RUN update-alternatives --install /usr/bin/aarch64-linux-gnu-gcc aarch64-linux-gnu-gcc /usr/bin/aarch64-linux-gnu-gcc-14 100 && \
+ update-alternatives --install /usr/bin/aarch64-linux-gnu-g++ aarch64-linux-gnu-g++ /usr/bin/aarch64-linux-gnu-g++-14 100
+
+RUN update-binfmts --enable qemu-s390x || true
+
+RUN update-binfmts --enable qemu-aarch64 || true
+
+RUN gcc --version && \
+ s390x-linux-gnu-gcc --version && \
+ s390x-linux-gnu-g++ --version
+
+RUN aarch64-linux-gnu-gcc --version && \
+ aarch64-linux-gnu-g++ --version
+
+RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal
+ENV PATH="/root/.cargo/bin:${PATH}"
+RUN rustup target add s390x-unknown-linux-gnu
+
+RUN rustup target add aarch64-unknown-linux-gnu
+
+ENV CARGO_TARGET_S390X_UNKNOWN_LINUX_GNU_LINKER=s390x-linux-gnu-gcc \
+ CARGO_TARGET_S390X_UNKNOWN_LINUX_GNU_RUNNER="qemu-s390x-static -L /usr/s390x-linux-gnu" \
+ CC_s390x_unknown_linux_gnu=s390x-linux-gnu-gcc \
+ CXX_s390x_unknown_linux_gnu=s390x-linux-gnu-g++ \
+ CXXFLAGS_s390x_unknown_linux_gnu="-std=c++17"
+
+ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \
+ CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER="qemu-aarch64-static -L /usr/aarch64-linux-gnu" \
+ CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc \
+ CXX_aarch64_unknown_linux_gnu=aarch64-linux-gnu-g++ \
+ CXXFLAGS_aarch64_unknown_linux_gnu="-std=c++17"
diff --git a/.github/workflows/cron-daily-fuzz.yml b/.github/workflows/cron-daily-fuzz.yml
index 50658c9f..39919eda 100644
--- a/.github/workflows/cron-daily-fuzz.yml
+++ b/.github/workflows/cron-daily-fuzz.yml
@@ -59,7 +59,6 @@ jobs:
with:
persist-credentials: false
- uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
-
id: cache-fuzz
with:
path: |
@@ -97,4 +96,4 @@ jobs:
- name: Display structure of downloaded files
run: ls -R
- run: find executed_* -type f -exec cat {} + | sort > executed
- - run: source ./fuzz/fuzz-util.sh && listTargetNames | sort | diff - executed
+ - run: cargo fuzz list | sort | diff - executed
diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml
index 407ac752..08369d5c 100644
--- a/.github/workflows/rust.yml
+++ b/.github/workflows/rust.yml
@@ -173,8 +173,15 @@ jobs:
persist-credentials: false
- name: "Select toolchain"
uses: dtolnay/rust-toolchain@5d458579430fc14a04a08a1e7d3694f545e91ce6 # stable
- - name: "Add architecture i386"
- run: sudo dpkg --add-architecture i386
+ - name: "Add architecture i386 and install dependencies"
+ run: |
+ sudo dpkg --add-architecture i386
+ sudo apt-get update -y
+ sudo apt-get install -y \
+ gcc-multilib \
+ g++-multilib \
+ libc6-dev-i386 \
+ lib32stdc++-13-dev
- name: "Install i686 gcc"
run: sudo apt-get update -y && sudo apt-get install -y gcc-multilib
- name: "Install target"
diff --git a/.gitignore b/.gitignore
index ab54b690..76e87b91 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,10 +15,7 @@ hashes/target
# Test artifacts
bitcoin/dep_test
mutants.out*
-
-# Fuzz artifacts
-hfuzz_target
-hfuzz_workspace
+fuzz/coverage
# Local tooling
.maintainer-tools
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index c4d0a7f8..97f6ad43 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -314,7 +314,7 @@ the project to enable fine-grained unit testing is also an ongoing effort.
Unit and integration tests are available for those interested, along with benchmarks. For project
developers, especially new contributors looking for something to work on, we do:
-- Fuzz testing with [`Honggfuzz`](https://github.com/rust-fuzz/honggfuzz-rs)
+- Fuzz testing with [`libfuzzer`](https://github.com/rust-fuzz/libfuzzer)
- Mutation testing with [`cargo-mutants`](https://github.com/sourcefrog/cargo-mutants)
- Code verification with [`Kani`](https://github.com/model-checking/kani)
diff --git a/Cargo-minimal.lock b/Cargo-minimal.lock
index 9a08ea82..31c0a8de 100644
--- a/Cargo-minimal.lock
+++ b/Cargo-minimal.lock
@@ -99,7 +99,7 @@ dependencies = [
"bitcoin",
"bitcoin-consensus-encoding",
"bitcoin-p2p-messages",
- "honggfuzz",
+ "libfuzzer-sys",
"serde",
"serde_json",
"standard_test",
@@ -275,30 +275,12 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd"
-[[package]]
-name = "honggfuzz"
-version = "0.5.58"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e8319f3cc8fe416e7aa1ab95dcc04fd49f35397a47d0b2f0f225f6dba346a07"
-dependencies = [
- "lazy_static",
- "memmap2",
- "rustc_version",
- "semver",
-]
-
[[package]]
name = "itoa"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
-[[package]]
-name = "lazy_static"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
-
[[package]]
name = "libc"
version = "0.2.155"
@@ -306,12 +288,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]]
-name = "memmap2"
-version = "0.9.0"
+name = "libfuzzer-sys"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "deaba38d7abf1d4cca21cc89e932e542ba2b9258664d2a9ef0e61512039c9375"
+checksum = "86c975d637bc2a2f99440932b731491fc34c7f785d239e38af3addd3c2fd0e46"
dependencies = [
- "libc",
+ "arbitrary",
+ "cc",
]
[[package]]
@@ -369,15 +352,6 @@ dependencies = [
"zerocopy",
]
-[[package]]
-name = "rustc_version"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
-dependencies = [
- "semver",
-]
-
[[package]]
name = "ryu"
version = "1.0.0"
@@ -404,12 +378,6 @@ dependencies = [
"cc",
]
-[[package]]
-name = "semver"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "76b5842e81eb9bbea19276a9dbbda22ac042532f390a67ab08b895617978abf3"
-
[[package]]
name = "serde"
version = "1.0.195"
diff --git a/Cargo-recent.lock b/Cargo-recent.lock
index cf257409..2e731623 100644
--- a/Cargo-recent.lock
+++ b/Cargo-recent.lock
@@ -98,7 +98,7 @@ dependencies = [
"bitcoin",
"bitcoin-consensus-encoding",
"bitcoin-p2p-messages",
- "honggfuzz",
+ "libfuzzer-sys",
"serde",
"serde_json",
"standard_test",
@@ -213,6 +213,8 @@ version = "1.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0"
dependencies = [
+ "jobserver",
+ "libc",
"shlex",
]
@@ -271,18 +273,6 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd"
-[[package]]
-name = "honggfuzz"
-version = "0.5.58"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e8319f3cc8fe416e7aa1ab95dcc04fd49f35397a47d0b2f0f225f6dba346a07"
-dependencies = [
- "lazy_static",
- "memmap2",
- "rustc_version",
- "semver",
-]
-
[[package]]
name = "itoa"
version = "1.0.11"
@@ -290,10 +280,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
-name = "lazy_static"
-version = "1.5.0"
+name = "jobserver"
+version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
+dependencies = [
+ "libc",
+]
[[package]]
name = "libc"
@@ -302,19 +295,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
[[package]]
-name = "memchr"
-version = "2.7.4"
+name = "libfuzzer-sys"
+version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+checksum = "5037190e1f70cbeef565bd267599242926f724d3b8a9f510fd7e0b540cfa4404"
+dependencies = [
+ "arbitrary",
+ "cc",
+]
[[package]]
-name = "memmap2"
-version = "0.9.5"
+name = "memchr"
+version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f"
-dependencies = [
- "libc",
-]
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "ppv-lite86"
@@ -378,15 +372,6 @@ dependencies = [
"getrandom",
]
-[[package]]
-name = "rustc_version"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
-dependencies = [
- "semver",
-]
-
[[package]]
name = "ryu"
version = "1.0.18"
@@ -413,12 +398,6 @@ dependencies = [
"cc",
]
-[[package]]
-name = "semver"
-version = "1.0.23"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
-
[[package]]
name = "serde"
version = "1.0.210"
diff --git a/Cross.toml b/Cross.toml
new file mode 100644
index 00000000..c7f4776e
--- /dev/null
+++ b/Cross.toml
@@ -0,0 +1,5 @@
+[target.s390x-unknown-linux-gnu]
+dockerfile = ".github/docker/Dockerfile.cross"
+
+[target.aarch64-unknown-linux-gnu]
+dockerfile = ".github/docker/Dockerfile.cross"
diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml
index 4c6ee387..f798ef5d 100644
--- a/fuzz/Cargo.toml
+++ b/fuzz/Cargo.toml
@@ -10,12 +10,12 @@ publish = false
cargo-fuzz = true
[dependencies]
-honggfuzz = { version = "0.5.58", default-features = false }
bitcoin = { path = "../bitcoin", features = [ "serde", "arbitrary" ] }
-p2p = { path = "../p2p", package = "bitcoin-p2p-messages", features = ["arbitrary"] }
bitcoin_consensus_encoding = { path = "../consensus_encoding", package = "bitcoin-consensus-encoding" }
-arbitrary = { version = "1.4.1" }
+p2p = { path = "../p2p", package = "bitcoin-p2p-messages", features = ["arbitrary"] }
+arbitrary = { version = "1.4.1" }
+libfuzzer-sys = { version = "0.4.0" }
serde = { version = "1.0.195", features = [ "derive" ] }
serde_json = "1.0.68"
standard_test = "0.1.0"
@@ -30,119 +30,209 @@ use_self = "warn"
[[bin]]
name = "bitcoin_arbitrary_block"
path = "fuzz_targets/bitcoin/arbitrary_block.rs"
+test = false
+doc = false
+bench = false
[[bin]]
name = "bitcoin_arbitrary_script"
path = "fuzz_targets/bitcoin/arbitrary_script.rs"
+test = false
+doc = false
+bench = false
[[bin]]
name = "bitcoin_arbitrary_transaction"
path = "fuzz_targets/bitcoin/arbitrary_transaction.rs"
+test = false
+doc = false
+bench = false
[[bin]]
name = "bitcoin_arbitrary_witness"
path = "fuzz_targets/bitcoin/arbitrary_witness.rs"
+test = false
+doc = false
+bench = false
[[bin]]
name = "bitcoin_deserialize_block"
path = "fuzz_targets/bitcoin/deserialize_block.rs"
+test = false
+doc = false
+bench = false
[[bin]]
name = "bitcoin_deserialize_prefilled_transaction"
path = "fuzz_targets/bitcoin/deserialize_prefilled_transaction.rs"
+test = false
+doc = false
+bench = false
[[bin]]
name = "bitcoin_deserialize_psbt"
path = "fuzz_targets/bitcoin/deserialize_psbt.rs"
+test = false
+doc = false
+bench = false
[[bin]]
name = "bitcoin_deserialize_script"
path = "fuzz_targets/bitcoin/deserialize_script.rs"
+test = false
+doc = false
+bench = false
[[bin]]
name = "bitcoin_deserialize_transaction"
path = "fuzz_targets/bitcoin/deserialize_transaction.rs"
+test = false
+doc = false
+bench = false
[[bin]]
name = "bitcoin_deserialize_witness"
path = "fuzz_targets/bitcoin/deserialize_witness.rs"
+test = false
+doc = false
+bench = false
[[bin]]
name = "bitcoin_parse_address"
path = "fuzz_targets/bitcoin/parse_address.rs"
+test = false
+doc = false
+bench = false
[[bin]]
name = "bitcoin_parse_outpoint"
path = "fuzz_targets/bitcoin/parse_outpoint.rs"
+test = false
+doc = false
+bench = false
[[bin]]
name = "bitcoin_script_bytes_to_asm_fmt"
path = "fuzz_targets/bitcoin/script_bytes_to_asm_fmt.rs"
+test = false
+doc = false
+bench = false
[[bin]]
name = "consensus_encoding_decode_array"
path = "fuzz_targets/consensus_encoding/decode_array.rs"
+test = false
+doc = false
+bench = false
[[bin]]
name = "consensus_encoding_decode_byte_vec"
path = "fuzz_targets/consensus_encoding/decode_byte_vec.rs"
+test = false
+doc = false
+bench = false
[[bin]]
name = "consensus_encoding_decode_compact_size"
path = "fuzz_targets/consensus_encoding/decode_compact_size.rs"
+test = false
+doc = false
+bench = false
[[bin]]
name = "consensus_encoding_decode_decoder2"
path = "fuzz_targets/consensus_encoding/decode_decoder2.rs"
+test = false
+doc = false
+bench = false
[[bin]]
name = "hashes_json"
path = "fuzz_targets/hashes/json.rs"
+test = false
+doc = false
+bench = false
[[bin]]
name = "hashes_ripemd160"
path = "fuzz_targets/hashes/ripemd160.rs"
+test = false
+doc = false
+bench = false
[[bin]]
name = "hashes_sha1"
path = "fuzz_targets/hashes/sha1.rs"
+test = false
+doc = false
+bench = false
[[bin]]
name = "hashes_sha256"
path = "fuzz_targets/hashes/sha256.rs"
+test = false
+doc = false
+bench = false
[[bin]]
name = "hashes_sha512"
path = "fuzz_targets/hashes/sha512.rs"
+test = false
+doc = false
+bench = false
[[bin]]
name = "hashes_sha512_256"
path = "fuzz_targets/hashes/sha512_256.rs"
+test = false
+doc = false
+bench = false
[[bin]]
name = "p2p_arbitrary_addrv2"
path = "fuzz_targets/p2p/arbitrary_addrv2.rs"
+test = false
+doc = false
+bench = false
[[bin]]
name = "p2p_deserialize_addrv2"
path = "fuzz_targets/p2p/deserialize_addrv2.rs"
+test = false
+doc = false
+bench = false
[[bin]]
name = "p2p_deserialize_raw_net_msg"
path = "fuzz_targets/p2p/deserialize_raw_net_msg.rs"
+test = false
+doc = false
+bench = false
[[bin]]
name = "units_arbitrary_weight"
path = "fuzz_targets/units/arbitrary_weight.rs"
+test = false
+doc = false
+bench = false
[[bin]]
name = "units_parse_amount"
path = "fuzz_targets/units/parse_amount.rs"
+test = false
+doc = false
+bench = false
[[bin]]
name = "units_parse_int"
path = "fuzz_targets/units/parse_int.rs"
+test = false
+doc = false
+bench = false
[[bin]]
name = "units_standard_checks"
path = "fuzz_targets/units/standard_checks.rs"
+test = false
+doc = false
+bench = false
diff --git a/fuzz/README.md b/fuzz/README.md
index 38b7d854..15120dee 100644
--- a/fuzz/README.md
+++ b/fuzz/README.md
@@ -1,7 +1,7 @@
# Fuzzing
-`bitcoin` and `bitcoin_hashes` have fuzzing harnesses setup for use with
-honggfuzz.
+`rust-bitcoin` has fuzzing harnesses setup for use with
+`cargo-fuzz`.
To run the fuzz-tests as in CI -- briefly fuzzing every target -- simply
run
@@ -12,18 +12,6 @@ run
in this directory.
-To build honggfuzz, you must have libunwind on your system, as well as
-libopcodes and libbfd from binutils **2.38** on your system. The most
-recently-released binutils 2.39 has changed their API in a breaking way.
-
-On Nix, you can obtain these libraries by running
-
-```bash
-nix-shell -p libopcodes_2_38 -p libunwind
-```
-
-and then run `fuzz.sh` as above.
-
## Fuzzing with weak cryptography
You may wish to replace the hashing and signing code with broken crypto,
@@ -32,7 +20,7 @@ things such as forging signatures or finding preimages to hashes.
Doing so may result in spurious bug reports since the broken crypto does
not respect the encoding or algebraic invariants upheld by the real crypto. We
-would like to improve this but it's a nontrivial problem -- though not
+would like to improve this, but it's a nontrivial problem -- though not
beyond the abilities of a motivated student with a few months of time.
Please let us know if you are interested in taking this on!
@@ -54,8 +42,7 @@ fuzzer can break your crypto, so can anybody.
To see the full list of targets, the most straightforward way is to run
```bash
-source ./fuzz-util.sh
-listTargetNames
+cargo fuzz list
```
To run each of them for an hour, run
@@ -63,18 +50,17 @@ To run each of them for an hour, run
```bash
./cycle.sh
```
+This script uses the `chrt` utility to try to reduce the priority of the
+jobs. If you would like to run for longer, the most straightforward way
+is to edit `cycle.sh` before starting. To run the fuzz-tests in parallel,
+you will need to implement a custom harness.
To run a single fuzztest indefinitely, run
```bash
-HFUZZ_BUILD_ARGS='--features honggfuzz_fuzz' cargo hfuzz run <target>
+cargo +nightly fuzz run "<target>"
```
-This script uses the `chrt` utility to try to reduce the priority of the
-jobs. If you would like to run for longer, the most straightforward way
-is to edit `cycle.sh` before starting. To run the fuzz-tests in parallel,
-you will need to implement a custom harness.
-
## Adding fuzz tests
All fuzz tests can be found in the `fuzz_target/` directory. Adding a new
@@ -82,7 +68,7 @@ one is as simple as copying an existing one and editing the `do_test`
function to do what you want.
If your test clearly belongs to a specific crate, please put it in that
-crate's directory. Otherwise you can put it directly in `fuzz_target/`.
+crate's directory. Otherwise, you can put it directly in `fuzz_target/`.
If you need to add dependencies, edit the file `generate-files.sh` to add
it to the generated `Cargo.toml`.
@@ -101,32 +87,68 @@ Then to test your fuzztest, run
```
If it is working, you will see a rapid stream of data for many seconds
-(you can hit Ctrl+C to stop it early). If not, you should quickly see
-an error.
+(you can hit Ctrl+C to stop it early) that looks something like this:
+```text
+INFO: Running with entropic power schedule (0xFF, 100).
+INFO: Seed: 2953319389
+INFO: Loaded 1 modules (9121 inline 8-bit counters): 9121 [0x104132ea0, 0x104135241),
+INFO: Loaded 1 PC tables (9121 PCs): 9121 [0x104135248,0x104158c58),
+INFO: 0 files found in /some/path/to/rust-bitcoin/fuzz/corpus/units_arbitrary_weight
+INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
+INFO: A corpus is not provided, starting from an empty corpus
+#2 INITED cov: 42 ft: 42 corp: 1/1b exec/s: 0 rss: 36Mb
+#411 NEW cov: 43 ft: 43 corp: 2/9b lim: 8 exec/s: 0 rss: 37Mb L: 8/8 MS: 4 ChangeBinInt-ShuffleBytes-ShuffleBytes-InsertRepeatedBytes-
+#1329 NEW cov: 43 ft: 44 corp: 3/26b lim: 17 exec/s: 0 rss: 37Mb L: 17/17 MS: 3 InsertRepeatedBytes-CMP-CopyPart- DE: "\001\000\000\000"-
+#1357 REDUCE cov: 43 ft: 44 corp: 3/25b lim: 17 exec/s: 0 rss: 37Mb L: 16/16 MS: 3 CopyPart-CMP-EraseBytes- DE: "\000\000\000\000\000\000\000\000"-
+...
+```
+If you don't see this, you should quickly see an error.
## Reproducing Failures
If a fuzztest fails, it will exit with a summary which looks something like
-
```text
...
- fuzzTarget : hfuzz_target/x86_64-unknown-linux-gnu/release/hashes_sha256
-CRASH:
-DESCRIPTION:
-ORIG_FNAME: 00000000000000000000000000000000.00000000.honggfuzz.cov
-FUZZ_FNAME: hfuzz_workspace/hashes_sha256/SIGABRT.PC.7ffff7c8abc7.STACK.18826d9b64.CODE.-6.ADDR.0.INSTR.mov____%eax,%ebp.fuzz
-...
-=====================================================================
-fff400610004
+thread '<unnamed>' (3001874) panicked at units/src/weight.rs:103:25:
+attempt to multiply with overflow
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
+==66478== ERROR: libFuzzer: deadly signal
+ #0 0x0001049fd3c4 in __sanitizer_print_stack_trace+0x28 (librustc-nightly_rt.asan.dylib:arm64+0x5d3c4)
+ #1 0x000104078b90 in fuzzer::PrintStackTrace()+0x30 (units_arbitrary_weight:arm64+0x100070b90)
+ #2 0x00010406d074 in fuzzer::Fuzzer::CrashCallback()+0x54 (units_arbitrary_weight:arm64+0x100065074)
+ #3 0x000180d26740 in _sigtramp+0x34 (libsystem_platform.dylib:arm64+0x3740)
+ ...
```
+This will tell you where the test failed and is followed by information about how to reproduce the crash.
+It will look something like this:
-The final line is a hex-encoded version of the input that caused the crash. You
-can test this directly by editing the `duplicate_crash` test to copy/paste the
-hex output into the call to `extend_vec_from_hex`. Then run the test with
+```text
+...
+NOTE: libFuzzer has rudimentary signal handlers.
+ Combine libFuzzer with AddressSanitizer or similar for better crash reports.
+SUMMARY: libFuzzer: deadly signal
+MS: 2 ChangeByte-CopyPart-; base unit: 25058c6b0d02cd1d71a030ad61c46b7396ddcdb9
+0x5e,0x5e,0x5e,0x5e,0x5e,0x44,0x0,0x0,0x0,0x0,0x0,0x5d,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x5e,0xa,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0xa5,0x1,0x1,0x1,
+^^^^^D\000\000\000\000\000]\001\000\000\000\000\000\000^\012\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\245\001\001\001
+artifact_prefix='/some/path/to/rust-bitcoin/fuzz/artifacts/units_arbitrary_weight/'; Test unit written to /some/path/to/rust-bitcoin/fuzz/artifacts/units_arbitrary_weight/crash-1b454523d38a6c3f45d453dfea4099f3cb574822
+Base64: Xl5eXl5EAAAAAABdAQAAAAAAAF4KAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBpQEBAQ==
+────────────────────────────────────────────────────────────────────────────────
-```bash
-cargo test
-```
+Failing input:
-Note that if you set your `RUSTFLAGS` while fuzzing (see above) you must make
-sure they are set the same way when running `cargo test`.
+ fuzz/artifacts/units_arbitrary_weight/crash-1b454523d38a6c3f45d453dfea4099f3cb574822
+
+Output of `std::fmt::Debug`:
+
+ [94, 94, 94, 94, 94, 68, 0, 0, 0, 0, 0, 93, 1, 0, 0, 0, 0, 0, 0, 94, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 165, 1, 1, 1]
+
+Reproduce with:
+
+ cargo fuzz run units_arbitrary_weight fuzz/artifacts/units_arbitrary_weight/crash-1b454523d38a6c3f45d453dfea4099f3cb574822
+
+Minimize test case with:
+
+ cargo fuzz tmin units_arbitrary_weight fuzz/artifacts/units_arbitrary_weight/crash-1b454523d38a6c3f45d453dfea4099f3cb574822
+
+────────────────────────────────────────────────────────────────────────────────
+```
diff --git a/fuzz/cycle.sh b/fuzz/cycle.sh
index c642157d..84c1cb6a 100755
--- a/fuzz/cycle.sh
+++ b/fuzz/cycle.sh
@@ -3,7 +3,7 @@
# Continuously cycle over fuzz targets running each for 1 hour.
# It uses chrt SCHED_IDLE so that other process takes priority.
#
-# For hfuzz options see https://github.com/google/honggfuzz/blob/master/docs/USAGE.md
+# For cargo-fuzz usage see https://github.com/rust-fuzz/cargo-fuzz?tab=readme-ov-file#usage
set -euo pipefail
@@ -19,9 +19,8 @@ do
echo "Fuzzing target $targetName ($targetFile)"
# fuzz for one hour
- HFUZZ_RUN_ARGS='--run_time 3600' chrt -i 0 cargo hfuzz run "$targetName"
- # minimize the corpus
- HFUZZ_RUN_ARGS="-i hfuzz_workspace/$targetName/input/ -P -M" chrt -i 0 cargo hfuzz run "$targetName"
+ chrt -i 0 cargo +nightly fuzz run "$targetName" -- -max_total_time=3600
+ cargo +nightly fuzz cmin "$targetName"
done
done
diff --git a/fuzz/fuzz-util.sh b/fuzz/fuzz-util.sh
index df53adde..5b63de9c 100755
--- a/fuzz/fuzz-util.sh
+++ b/fuzz/fuzz-util.sh
@@ -20,12 +20,6 @@ targetFileToName() {
| sed 's/^_//g'
}
-listTargetNames() {
- for target in $(listTargetFiles); do
- targetFileToName "$target"
- done
-}
-
# Utility function to avoid CI failures on Windows
checkWindowsFiles() {
incorrectFilenames=$(find . -type f -name "*,*" -o -name "*:*" -o -name "*<*" -o -name "*>*" -o -name "*|*" -o -name "*\?*" -o -name "*\**" -o -name "*\"*" | wc -l)
@@ -35,13 +29,16 @@ checkWindowsFiles() {
fi
}
-# Checks whether a fuzz case outputs some report, and dumps it in hex
+# Checks whether a fuzz case has artifacts, and dumps them in hex
checkReport() {
- reportFile="hfuzz_workspace/$1/HONGGFUZZ.REPORT.TXT"
- if [ -f "$reportFile" ]; then
- cat "$reportFile"
- for CASE in "hfuzz_workspace/$1/SIG"*; do
- xxd -p -c10000 < "$CASE"
+ artifactDir="fuzz/artifacts/$1"
+ if [ -d "$artifactDir" ] && [ -n "$(ls -A "$artifactDir" 2>/dev/null)" ]; then
+ echo "Artifacts found for target: $1"
+ for artifact in "$artifactDir"/*; do
+ if [ -f "$artifact" ]; then
+ echo "Artifact: $(basename "$artifact")"
+ xxd -p -c10000 < "$artifact"
+ fi
done
exit 1
fi
diff --git a/fuzz/fuzz.sh b/fuzz/fuzz.sh
index 897b29a0..e53f1861 100755
--- a/fuzz/fuzz.sh
+++ b/fuzz/fuzz.sh
@@ -1,4 +1,7 @@
#!/usr/bin/env bash
+# This script is used to briefly fuzz every target when no target is provided. Otherwise, it will briefly fuzz the
+# provided target
+
set -euox pipefail
REPO_DIR=$(git rev-parse --show-toplevel)
@@ -20,16 +23,11 @@ cargo --version
rustc --version
# Testing
-cargo install --force honggfuzz --no-default-features
+cargo install --force cargo-fuzz
for targetFile in $targetFiles; do
targetName=$(targetFileToName "$targetFile")
echo "Fuzzing target $targetName ($targetFile)"
- if [ -d "hfuzz_input/$targetName" ]; then
- HFUZZ_INPUT_ARGS="-f hfuzz_input/$targetName/input"
- else
- HFUZZ_INPUT_ARGS=""
- fi
- HFUZZ_RUN_ARGS="--run_time 3600 --exit_upon_crash -v $HFUZZ_INPUT_ARGS" cargo hfuzz run "$targetName"
-
+ # cargo-fuzz will check for the corpus at fuzz/corpus/<target>
+ cargo +nightly fuzz run "$targetName" -- -runs=100000
checkReport "$targetName"
done
diff --git a/fuzz/fuzz_targets/bitcoin/arbitrary_block.rs b/fuzz/fuzz_targets/bitcoin/arbitrary_block.rs
index 6c66bbc6..4dd36eeb 100644
--- a/fuzz/fuzz_targets/bitcoin/arbitrary_block.rs
+++ b/fuzz/fuzz_targets/bitcoin/arbitrary_block.rs
@@ -1,7 +1,14 @@
+#![cfg_attr(fuzzing, no_main)]
+#![cfg_attr(not(fuzzing), allow(unused))]
+
+use libfuzzer_sys::fuzz_target;
use arbitrary::{Arbitrary, Unstructured};
+
use bitcoin::block::{self, Block, BlockCheckedExt as _};
use bitcoin::consensus::{deserialize, serialize};
-use honggfuzz::fuzz;
+
+#[cfg(not(fuzzing))]
+fn main() {}
fn do_test(data: &[u8]) {
let mut u = Unstructured::new(data);
@@ -28,37 +35,6 @@ fn do_test(data: &[u8]) {
}
}
-fn main() {
- loop {
- fuzz!(|data| {
- do_test(data);
- });
- }
-}
-
-#[cfg(all(test, fuzzing))]
-mod tests {
- fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
- let mut b = 0;
- for (idx, c) in hex.as_bytes().iter().enumerate() {
- b <<= 4;
- match *c {
- b'A'..=b'F' => b |= c - b'A' + 10,
- b'a'..=b'f' => b |= c - b'a' + 10,
- b'0'..=b'9' => b |= c - b'0',
- _ => panic!("Bad hex"),
- }
- if (idx & 1) == 1 {
- out.push(b);
- b = 0;
- }
- }
- }
-
- #[test]
- fn duplicate_crash() {
- let mut a = Vec::new();
- extend_vec_from_hex("00", &mut a);
- super::do_test(&a);
- }
-}
+fuzz_target!(|data| {
+ do_test(data);
+});
diff --git a/fuzz/fuzz_targets/bitcoin/arbitrary_script.rs b/fuzz/fuzz_targets/bitcoin/arbitrary_script.rs
index 4fd4dc07..6ffb7a83 100644
--- a/fuzz/fuzz_targets/bitcoin/arbitrary_script.rs
+++ b/fuzz/fuzz_targets/bitcoin/arbitrary_script.rs
@@ -1,9 +1,16 @@
+#![cfg_attr(fuzzing, no_main)]
+#![cfg_attr(not(fuzzing), allow(unused))]
+
+use libfuzzer_sys::fuzz_target;
use arbitrary::{Arbitrary, Unstructured};
+
use bitcoin::address::Address;
use bitcoin::consensus::serialize;
use bitcoin::script::{self, ScriptBuf, ScriptExt as _, ScriptPubKeyExt as _};
use bitcoin::Network;
-use honggfuzz::fuzz;
+
+#[cfg(not(fuzzing))]
+fn main() {}
fn do_test(data: &[u8]) {
let mut u = Unstructured::new(data);
@@ -48,37 +55,6 @@ fn do_test(data: &[u8]) {
}
}
-fn main() {
- loop {
- fuzz!(|data| {
- do_test(data);
- });
- }
-}
-
-#[cfg(all(test, fuzzing))]
-mod tests {
- fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
- let mut b = 0;
- for (idx, c) in hex.as_bytes().iter().enumerate() {
- b <<= 4;
- match *c {
- b'A'..=b'F' => b |= c - b'A' + 10,
- b'a'..=b'f' => b |= c - b'a' + 10,
- b'0'..=b'9' => b |= c - b'0',
- _ => panic!("Bad hex"),
- }
- if (idx & 1) == 1 {
- out.push(b);
- b = 0;
- }
- }
- }
-
- #[test]
- fn duplicate_crash() {
- let mut a = Vec::new();
- extend_vec_from_hex("00", &mut a);
- super::do_test(&a);
- }
-}
+fuzz_target!(|data| {
+ do_test(data);
+});
diff --git a/fuzz/fuzz_targets/bitcoin/arbitrary_transaction.rs b/fuzz/fuzz_targets/bitcoin/arbitrary_transaction.rs
index be1005df..c115e905 100644
--- a/fuzz/fuzz_targets/bitcoin/arbitrary_transaction.rs
+++ b/fuzz/fuzz_targets/bitcoin/arbitrary_transaction.rs
@@ -1,8 +1,15 @@
+#![cfg_attr(fuzzing, no_main)]
+#![cfg_attr(not(fuzzing), allow(unused))]
+
+use libfuzzer_sys::fuzz_target;
use arbitrary::{Arbitrary, Unstructured};
+
use bitcoin::consensus::{deserialize, serialize};
use bitcoin::transaction::TransactionExt as _;
use bitcoin::Transaction;
-use honggfuzz::fuzz;
+
+#[cfg(not(fuzzing))]
+fn main() {}
fn do_test(data: &[u8]) {
let mut u = Unstructured::new(data);
@@ -31,37 +38,6 @@ fn do_test(data: &[u8]) {
}
}
-fn main() {
- loop {
- fuzz!(|data| {
- do_test(data);
- });
- }
-}
-
-#[cfg(all(test, fuzzing))]
-mod tests {
- fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
- let mut b = 0;
- for (idx, c) in hex.as_bytes().iter().enumerate() {
- b <<= 4;
- match *c {
- b'A'..=b'F' => b |= c - b'A' + 10,
- b'a'..=b'f' => b |= c - b'a' + 10,
- b'0'..=b'9' => b |= c - b'0',
- _ => panic!("Bad hex"),
- }
- if (idx & 1) == 1 {
- out.push(b);
- b = 0;
- }
- }
- }
-
- #[test]
- fn duplicate_crash() {
- let mut a = Vec::new();
- extend_vec_from_hex("00", &mut a);
- super::do_test(&a);
- }
-}
+fuzz_target!(|data| {
+ do_test(data);
+});
diff --git a/fuzz/fuzz_targets/bitcoin/arbitrary_witness.rs b/fuzz/fuzz_targets/bitcoin/arbitrary_witness.rs
index f4308ed7..0fca331a 100644
--- a/fuzz/fuzz_targets/bitcoin/arbitrary_witness.rs
+++ b/fuzz/fuzz_targets/bitcoin/arbitrary_witness.rs
@@ -1,8 +1,15 @@
+#![cfg_attr(fuzzing, no_main)]
+#![cfg_attr(not(fuzzing), allow(unused))]
+
+use libfuzzer_sys::fuzz_target;
use arbitrary::{Arbitrary, Unstructured};
-use bitcoin::blockdata::witness::WitnessExt;
+
use bitcoin::consensus::{deserialize, serialize};
use bitcoin::Witness;
-use honggfuzz::fuzz;
+use bitcoin::blockdata::witness::WitnessExt;
+
+#[cfg(not(fuzzing))]
+fn main() {}
fn do_test(data: &[u8]) {
let mut u = Unstructured::new(data);
@@ -22,37 +29,6 @@ fn do_test(data: &[u8]) {
}
}
-fn main() {
- loop {
- fuzz!(|data| {
- do_test(data);
- });
- }
-}
-
-#[cfg(all(test, fuzzing))]
-mod tests {
- fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
- let mut b = 0;
- for (idx, c) in hex.as_bytes().iter().enumerate() {
- b <<= 4;
- match *c {
- b'A'..=b'F' => b |= c - b'A' + 10,
- b'a'..=b'f' => b |= c - b'a' + 10,
- b'0'..=b'9' => b |= c - b'0',
- _ => panic!("Bad hex"),
- }
- if (idx & 1) == 1 {
- out.push(b);
- b = 0;
- }
- }
- }
-
- #[test]
- fn duplicate_crash() {
- let mut a = Vec::new();
- extend_vec_from_hex("00", &mut a);
- super::do_test(&a);
- }
-}
+fuzz_target!(|data| {
+ do_test(data);
+});
diff --git a/fuzz/fuzz_targets/bitcoin/deserialize_block.rs b/fuzz/fuzz_targets/bitcoin/deserialize_block.rs
index c9725106..b5136958 100644
--- a/fuzz/fuzz_targets/bitcoin/deserialize_block.rs
+++ b/fuzz/fuzz_targets/bitcoin/deserialize_block.rs
@@ -1,4 +1,10 @@
-use honggfuzz::fuzz;
+#![cfg_attr(fuzzing, no_main)]
+#![cfg_attr(not(fuzzing), allow(unused))]
+
+use libfuzzer_sys::fuzz_target;
+
+#[cfg(not(fuzzing))]
+fn main() {}
fn do_test(data: &[u8]) {
let block_result: Result<bitcoin::Block, _> = bitcoin::consensus::encode::deserialize(data);
@@ -12,37 +18,6 @@ fn do_test(data: &[u8]) {
}
}
-fn main() {
- loop {
- fuzz!(|data| {
- do_test(data);
- });
- }
-}
-
-#[cfg(all(test, fuzzing))]
-mod tests {
- fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
- let mut b = 0;
- for (idx, c) in hex.as_bytes().iter().enumerate() {
- b <<= 4;
- match *c {
- b'A'..=b'F' => b |= c - b'A' + 10,
- b'a'..=b'f' => b |= c - b'a' + 10,
- b'0'..=b'9' => b |= c - b'0',
- _ => panic!("Bad hex"),
- }
- if (idx & 1) == 1 {
- out.push(b);
- b = 0;
- }
- }
- }
-
- #[test]
- fn duplicate_crash() {
- let mut a = Vec::new();
- extend_vec_from_hex("000700000001000000010000", &mut a);
- super::do_test(&a);
- }
-}
+fuzz_target!(|data| {
+ do_test(data);
+});
diff --git a/fuzz/fuzz_targets/bitcoin/deserialize_prefilled_transaction.rs b/fuzz/fuzz_targets/bitcoin/deserialize_prefilled_transaction.rs
index 948f77ef..1fadf12f 100644
--- a/fuzz/fuzz_targets/bitcoin/deserialize_prefilled_transaction.rs
+++ b/fuzz/fuzz_targets/bitcoin/deserialize_prefilled_transaction.rs
@@ -1,4 +1,10 @@
-use honggfuzz::fuzz;
+#![cfg_attr(fuzzing, no_main)]
+#![cfg_attr(not(fuzzing), allow(unused))]
+
+use libfuzzer_sys::fuzz_target;
+
+#[cfg(not(fuzzing))]
+fn main() {}
fn do_test(data: &[u8]) {
// We already fuzz Transactions in `./deserialize_transaction.rs`.
@@ -14,37 +20,6 @@ fn do_test(data: &[u8]) {
}
}
-fn main() {
- loop {
- fuzz!(|data| {
- do_test(data);
- });
- }
-}
-
-#[cfg(all(test, fuzzing))]
-mod tests {
- fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
- let mut b = 0;
- for (idx, c) in hex.as_bytes().iter().enumerate() {
- b <<= 4;
- match *c {
- b'A'..=b'F' => b |= c - b'A' + 10,
- b'a'..=b'f' => b |= c - b'a' + 10,
- b'0'..=b'9' => b |= c - b'0',
- _ => panic!("Bad hex"),
- }
- if (idx & 1) == 1 {
- out.push(b);
- b = 0;
- }
- }
- }
-
- #[test]
- fn duplicate_crash() {
- let mut a = Vec::new();
- extend_vec_from_hex("00000000", &mut a);
- super::do_test(&a);
- }
-}
+fuzz_target!(|data| {
+ do_test(data);
+});
diff --git a/fuzz/fuzz_targets/bitcoin/deserialize_psbt.rs b/fuzz/fuzz_targets/bitcoin/deserialize_psbt.rs
index c0d73691..698b803e 100644
--- a/fuzz/fuzz_targets/bitcoin/deserialize_psbt.rs
+++ b/fuzz/fuzz_targets/bitcoin/deserialize_psbt.rs
@@ -1,5 +1,11 @@
+#![cfg_attr(fuzzing, no_main)]
+#![cfg_attr(not(fuzzing), allow(unused))]
+
+use libfuzzer_sys::fuzz_target;
use arbitrary::{Arbitrary, Unstructured};
-use honggfuzz::fuzz;
+
+#[cfg(not(fuzzing))]
+fn main() {}
fn do_test(data: &[u8]) {
let mut unstructured = Unstructured::new(data);
@@ -27,37 +33,6 @@ fn do_test(data: &[u8]) {
assert_eq!(psbt_b.combine(psbt_a).is_ok(), psbt_a_clone.combine(psbt_b).is_ok());
}
-fn main() {
- loop {
- fuzz!(|data| {
- do_test(data);
- });
- }
-}
-
-#[cfg(all(test, fuzzing))]
-mod tests {
- fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
- let mut b = 0;
- for (idx, c) in hex.as_bytes().iter().enumerate() {
- b <<= 4;
- match *c {
- b'A'..=b'F' => b |= c - b'A' + 10,
- b'a'..=b'f' => b |= c - b'a' + 10,
- b'0'..=b'9' => b |= c - b'0',
- _ => panic!("Bad hex"),
- }
- if (idx & 1) == 1 {
- out.push(b);
- b = 0;
- }
- }
- }
-
- #[test]
- fn duplicate_crash() {
- let mut a = Vec::new();
- extend_vec_from_hex("00", &mut a);
- super::do_test(&a);
- }
-}
+fuzz_target!(|data| {
+ do_test(data);
+});
diff --git a/fuzz/fuzz_targets/bitcoin/deserialize_script.rs b/fuzz/fuzz_targets/bitcoin/deserialize_script.rs
index 407d03c7..6d9bb129 100644
--- a/fuzz/fuzz_targets/bitcoin/deserialize_script.rs
+++ b/fuzz/fuzz_targets/bitcoin/deserialize_script.rs
@@ -1,4 +1,10 @@
-use honggfuzz::fuzz;
+#![cfg_attr(fuzzing, no_main)]
+#![cfg_attr(not(fuzzing), allow(unused))]
+
+use libfuzzer_sys::fuzz_target;
+
+#[cfg(not(fuzzing))]
+fn main() {}
fn do_test(data: &[u8]) {
let script_result: Result<bitcoin::ScriptPubKeyBuf, _> =
@@ -13,37 +19,6 @@ fn do_test(data: &[u8]) {
}
}
-fn main() {
- loop {
- fuzz!(|data| {
- do_test(data);
- });
- }
-}
-
-#[cfg(all(test, fuzzing))]
-mod tests {
- fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
- let mut b = 0;
- for (idx, c) in hex.as_bytes().iter().enumerate() {
- b <<= 4;
- match *c {
- b'A'..=b'F' => b |= c - b'A' + 10,
- b'a'..=b'f' => b |= c - b'a' + 10,
- b'0'..=b'9' => b |= c - b'0',
- _ => panic!("Bad hex"),
- }
- if (idx & 1) == 1 {
- out.push(b);
- b = 0;
- }
- }
- }
-
- #[test]
- fn duplicate_crash() {
- let mut a = Vec::new();
- extend_vec_from_hex("00", &mut a);
- super::do_test(&a);
- }
-}
+fuzz_target!(|data| {
+ do_test(data);
+});
diff --git a/fuzz/fuzz_targets/bitcoin/deserialize_transaction.rs b/fuzz/fuzz_targets/bitcoin/deserialize_transaction.rs
index 340b596b..4595ed11 100644
--- a/fuzz/fuzz_targets/bitcoin/deserialize_transaction.rs
+++ b/fuzz/fuzz_targets/bitcoin/deserialize_transaction.rs
@@ -1,4 +1,10 @@
-use honggfuzz::fuzz;
+#![cfg_attr(fuzzing, no_main)]
+#![cfg_attr(not(fuzzing), allow(unused))]
+
+use libfuzzer_sys::fuzz_target;
+
+#[cfg(not(fuzzing))]
+fn main() {}
fn do_test(data: &[u8]) {
let tx_result: Result<bitcoin::Transaction, _> = bitcoin::consensus::encode::deserialize(data);
@@ -12,37 +18,6 @@ fn do_test(data: &[u8]) {
}
}
-fn main() {
- loop {
- fuzz!(|data| {
- do_test(data);
- });
- }
-}
-
-#[cfg(all(test, fuzzing))]
-mod tests {
- fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
- let mut b = 0;
- for (idx, c) in hex.as_bytes().iter().enumerate() {
- b <<= 4;
- match *c {
- b'A'..=b'F' => b |= c - b'A' + 10,
- b'a'..=b'f' => b |= c - b'a' + 10,
- b'0'..=b'9' => b |= c - b'0',
- _ => panic!("Bad hex"),
- }
- if (idx & 1) == 1 {
- out.push(b);
- b = 0;
- }
- }
- }
-
- #[test]
- fn duplicate_crash() {
- let mut a = Vec::new();
- extend_vec_from_hex("00", &mut a);
- super::do_test(&a);
- }
-}
+fuzz_target!(|data| {
+ do_test(data);
+});
diff --git a/fuzz/fuzz_targets/bitcoin/deserialize_witness.rs b/fuzz/fuzz_targets/bitcoin/deserialize_witness.rs
index ecc59b9e..b325bbaa 100644
--- a/fuzz/fuzz_targets/bitcoin/deserialize_witness.rs
+++ b/fuzz/fuzz_targets/bitcoin/deserialize_witness.rs
@@ -1,5 +1,12 @@
+#![cfg_attr(fuzzing, no_main)]
+#![cfg_attr(not(fuzzing), allow(unused))]
+
+use libfuzzer_sys::fuzz_target;
+
use bitcoin::witness::Witness;
-use honggfuzz::fuzz;
+
+#[cfg(not(fuzzing))]
+fn main() {}
fn do_test(data: &[u8]) {
let witness_result: Result<Witness, _> = bitcoin::consensus::encode::deserialize(data);
@@ -13,37 +20,6 @@ fn do_test(data: &[u8]) {
}
}
-fn main() {
- loop {
- fuzz!(|data| {
- do_test(data);
- });
- }
-}
-
-#[cfg(all(test, fuzzing))]
-mod tests {
- fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
- let mut b = 0;
- for (idx, c) in hex.as_bytes().iter().enumerate() {
- b <<= 4;
- match *c {
- b'A'..=b'F' => b |= c - b'A' + 10,
- b'a'..=b'f' => b |= c - b'a' + 10,
- b'0'..=b'9' => b |= c - b'0',
- _ => panic!("Bad hex"),
- }
- if (idx & 1) == 1 {
- out.push(b);
- b = 0;
- }
- }
- }
-
- #[test]
- fn duplicate_crash() {
- let mut a = Vec::new();
- extend_vec_from_hex("00", &mut a);
- super::do_test(&a);
- }
-}
+fuzz_target!(|data| {
+ do_test(data);
+});
diff --git a/fuzz/fuzz_targets/bitcoin/parse_address.rs b/fuzz/fuzz_targets/bitcoin/parse_address.rs
index c862524a..570e123d 100644
--- a/fuzz/fuzz_targets/bitcoin/parse_address.rs
+++ b/fuzz/fuzz_targets/bitcoin/parse_address.rs
@@ -1,4 +1,10 @@
-use honggfuzz::fuzz;
+#![cfg_attr(fuzzing, no_main)]
+#![cfg_attr(not(fuzzing), allow(unused))]
+
+use libfuzzer_sys::fuzz_target;
+
+#[cfg(not(fuzzing))]
+fn main() {}
fn do_test(data: &[u8]) {
let data_str = String::from_utf8_lossy(data);
@@ -9,37 +15,6 @@ fn do_test(data: &[u8]) {
assert_eq!(addr.to_string(), data_str);
}
-fn main() {
- loop {
- fuzz!(|data| {
- do_test(data);
- });
- }
-}
-
-#[cfg(all(test, fuzzing))]
-mod tests {
- fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
- let mut b = 0;
- for (idx, c) in hex.as_bytes().iter().enumerate() {
- b <<= 4;
- match *c {
- b'A'..=b'F' => b |= c - b'A' + 10,
- b'a'..=b'f' => b |= c - b'a' + 10,
- b'0'..=b'9' => b |= c - b'0',
- _ => panic!("Bad hex"),
- }
- if (idx & 1) == 1 {
- out.push(b);
- b = 0;
- }
- }
- }
-
- #[test]
- fn duplicate_crash() {
- let mut a = Vec::new();
- extend_vec_from_hex("00000000", &mut a);
- super::do_test(&a);
- }
-}
+fuzz_target!(|data| {
+ do_test(data);
+});
diff --git a/fuzz/fuzz_targets/bitcoin/parse_outpoint.rs b/fuzz/fuzz_targets/bitcoin/parse_outpoint.rs
index 8d9fffec..ac852882 100644
--- a/fuzz/fuzz_targets/bitcoin/parse_outpoint.rs
+++ b/fuzz/fuzz_targets/bitcoin/parse_outpoint.rs
@@ -1,6 +1,13 @@
+#![cfg_attr(fuzzing, no_main)]
+#![cfg_attr(not(fuzzing), allow(unused))]
+
+use libfuzzer_sys::fuzz_target;
+
use bitcoin::consensus::encode;
use bitcoin::transaction::OutPoint;
-use honggfuzz::fuzz;
+
+#[cfg(not(fuzzing))]
+fn main() {}
fn do_test(data: &[u8]) {
let lowercase: Vec<u8> = data
@@ -39,37 +46,6 @@ fn do_test(data: &[u8]) {
}
}
-fn main() {
- loop {
- fuzz!(|data| {
- do_test(data);
- });
- }
-}
-
-#[cfg(all(test, fuzzing))]
-mod tests {
- fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
- let mut b = 0;
- for (idx, c) in hex.as_bytes().iter().enumerate() {
- b <<= 4;
- match *c {
- b'A'..=b'F' => b |= c - b'A' + 10,
- b'a'..=b'f' => b |= c - b'a' + 10,
- b'0'..=b'9' => b |= c - b'0',
- _ => panic!("Bad hex"),
- }
- if (idx & 1) == 1 {
- out.push(b);
- b = 0;
- }
- }
- }
-
- #[test]
- fn duplicate_crash() {
- let mut a = Vec::new();
- extend_vec_from_hex("00", &mut a);
- super::do_test(&a);
- }
-}
+fuzz_target!(|data| {
+ do_test(data);
+});
diff --git a/fuzz/fuzz_targets/bitcoin/script_bytes_to_asm_fmt.rs b/fuzz/fuzz_targets/bitcoin/script_bytes_to_asm_fmt.rs
index 07b4d1f8..19c00119 100644
--- a/fuzz/fuzz_targets/bitcoin/script_bytes_to_asm_fmt.rs
+++ b/fuzz/fuzz_targets/bitcoin/script_bytes_to_asm_fmt.rs
@@ -1,6 +1,8 @@
-use std::fmt::{self, Write as _};
+#![cfg_attr(fuzzing, no_main)]
+#![cfg_attr(not(fuzzing), allow(unused))]
-use honggfuzz::fuzz;
+use libfuzzer_sys::fuzz_target;
+use std::fmt::{self, Write as _};
// faster than String, we don't need to actually produce the value, just check absence of panics
struct NullWriter;
@@ -11,43 +13,15 @@ impl fmt::Write for NullWriter {
fn write_char(&mut self, _c: char) -> fmt::Result { Ok(()) }
}
+#[cfg(not(fuzzing))]
+fn main() {}
+
fn do_test(data: &[u8]) {
let mut writer = NullWriter;
let script = bitcoin::WitnessScript::from_bytes(data);
write!(writer, "{script}").unwrap();
}
-fn main() {
- loop {
- fuzz!(|data| {
- do_test(data);
- });
- }
-}
-
-#[cfg(all(test, fuzzing))]
-mod tests {
- fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
- let mut b = 0;
- for (idx, c) in hex.as_bytes().iter().enumerate() {
- b <<= 4;
- match *c {
- b'A'..=b'F' => b |= c - b'A' + 10,
- b'a'..=b'f' => b |= c - b'a' + 10,
- b'0'..=b'9' => b |= c - b'0',
- _ => panic!("Bad hex"),
- }
- if (idx & 1) == 1 {
- out.push(b);
- b = 0;
- }
- }
- }
-
- #[test]
- fn duplicate_crash() {
- let mut a = Vec::new();
- extend_vec_from_hex("00000", &mut a);
- super::do_test(&a);
- }
-}
+fuzz_target!(|data| {
+ do_test(data);
+});
diff --git a/fuzz/fuzz_targets/consensus_encoding/decode_array.rs b/fuzz/fuzz_targets/consensus_encoding/decode_array.rs
index d9945386..80b25dfb 100644
--- a/fuzz/fuzz_targets/consensus_encoding/decode_array.rs
+++ b/fuzz/fuzz_targets/consensus_encoding/decode_array.rs
@@ -1,5 +1,12 @@
+#![cfg_attr(fuzzing, no_main)]
+#![cfg_attr(not(fuzzing), allow(unused))]
+
+use libfuzzer_sys::fuzz_target;
+
use bitcoin_consensus_encoding::{ArrayDecoder, Decoder};
-use honggfuzz::fuzz;
+
+#[cfg(not(fuzzing))]
+fn main() {}
fn do_test(data: &[u8]) {
test_array_decoder::<1>(data);
@@ -49,37 +56,6 @@ fn test_array_decoder<const N: usize>(data: &[u8]) {
}
}
-fn main() {
- loop {
- fuzz!(|data| {
- do_test(data);
- });
- }
-}
-
-#[cfg(all(test, fuzzing))]
-mod tests {
- fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
- let mut b = 0;
- for (idx, c) in hex.as_bytes().iter().enumerate() {
- b <<= 4;
- match *c {
- b'A'..=b'F' => b |= c - b'A' + 10,
- b'a'..=b'f' => b |= c - b'a' + 10,
- b'0'..=b'9' => b |= c - b'0',
- _ => panic!("Bad hex"),
- }
- if (idx & 1) == 1 {
- out.push(b);
- b = 0;
- }
- }
- }
-
- #[test]
- fn duplicate_crash() {
- let mut a = Vec::new();
- extend_vec_from_hex("deadbeef", &mut a);
- super::do_test(&a);
- }
-}
+fuzz_target!(|data| {
+ do_test(data);
+});
diff --git a/fuzz/fuzz_targets/consensus_encoding/decode_byte_vec.rs b/fuzz/fuzz_targets/consensus_encoding/decode_byte_vec.rs
index 6119cbb4..8e1daf23 100644
--- a/fuzz/fuzz_targets/consensus_encoding/decode_byte_vec.rs
+++ b/fuzz/fuzz_targets/consensus_encoding/decode_byte_vec.rs
@@ -1,5 +1,12 @@
+#![cfg_attr(fuzzing, no_main)]
+#![cfg_attr(not(fuzzing), allow(unused))]
+
+use libfuzzer_sys::fuzz_target;
+
use bitcoin_consensus_encoding::{ByteVecDecoder, Decoder};
-use honggfuzz::fuzz;
+
+#[cfg(not(fuzzing))]
+fn main() {}
fn do_test(data: &[u8]) {
let mut decoder = ByteVecDecoder::new();
@@ -38,37 +45,6 @@ fn do_test(data: &[u8]) {
}
}
-fn main() {
- loop {
- fuzz!(|data| {
- do_test(data);
- });
- }
-}
-
-#[cfg(all(test, fuzzing))]
-mod tests {
- fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
- let mut b = 0;
- for (idx, c) in hex.as_bytes().iter().enumerate() {
- b <<= 4;
- match *c {
- b'A'..=b'F' => b |= c - b'A' + 10,
- b'a'..=b'f' => b |= c - b'a' + 10,
- b'0'..=b'9' => b |= c - b'0',
- _ => panic!("Bad hex"),
- }
- if (idx & 1) == 1 {
- out.push(b);
- b = 0;
- }
- }
- }
-
- #[test]
- fn duplicate_crash() {
- let mut a = Vec::new();
- extend_vec_from_hex("03010203", &mut a);
- super::do_test(&a);
- }
-}
+fuzz_target!(|data| {
+ do_test(data);
+});
diff --git a/fuzz/fuzz_targets/consensus_encoding/decode_compact_size.rs b/fuzz/fuzz_targets/consensus_encoding/decode_compact_size.rs
index e747495c..ab1d2fa7 100644
--- a/fuzz/fuzz_targets/consensus_encoding/decode_compact_size.rs
+++ b/fuzz/fuzz_targets/consensus_encoding/decode_compact_size.rs
@@ -1,5 +1,12 @@
+#![cfg_attr(fuzzing, no_main)]
+#![cfg_attr(not(fuzzing), allow(unused))]
+
+use libfuzzer_sys::fuzz_target;
+
use bitcoin_consensus_encoding::{CompactSizeDecoder, Decoder};
-use honggfuzz::fuzz;
+
+#[cfg(not(fuzzing))]
+fn main() {}
fn do_test(data: &[u8]) {
let mut decoder = CompactSizeDecoder::new();
@@ -48,37 +55,6 @@ fn do_test(data: &[u8]) {
}
}
-fn main() {
- loop {
- fuzz!(|data| {
- do_test(data);
- });
- }
-}
-
-#[cfg(all(test, fuzzing))]
-mod tests {
- fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
- let mut b = 0;
- for (idx, c) in hex.as_bytes().iter().enumerate() {
- b <<= 4;
- match *c {
- b'A'..=b'F' => b |= c - b'A' + 10,
- b'a'..=b'f' => b |= c - b'a' + 10,
- b'0'..=b'9' => b |= c - b'0',
- _ => panic!("Bad hex"),
- }
- if (idx & 1) == 1 {
- out.push(b);
- b = 0;
- }
- }
- }
-
- #[test]
- fn duplicate_crash() {
- let mut a = Vec::new();
- extend_vec_from_hex("fd0000", &mut a);
- super::do_test(&a);
- }
-}
+fuzz_target!(|data| {
+ do_test(data);
+});
diff --git a/fuzz/fuzz_targets/consensus_encoding/decode_decoder2.rs b/fuzz/fuzz_targets/consensus_encoding/decode_decoder2.rs
index 774b3000..3b4219c1 100644
--- a/fuzz/fuzz_targets/consensus_encoding/decode_decoder2.rs
+++ b/fuzz/fuzz_targets/consensus_encoding/decode_decoder2.rs
@@ -1,5 +1,12 @@
+#![cfg_attr(fuzzing, no_main)]
+#![cfg_attr(not(fuzzing), allow(unused))]
+
+use libfuzzer_sys::fuzz_target;
+
use bitcoin_consensus_encoding::{ArrayDecoder, Decoder, Decoder2};
-use honggfuzz::fuzz;
+
+#[cfg(not(fuzzing))]
+fn main() {}
fn do_test(data: &[u8]) {
let mut decoder = Decoder2::new(ArrayDecoder::<2>::new(), ArrayDecoder::<3>::new());
@@ -39,37 +46,7 @@ fn do_test(data: &[u8]) {
}
}
-fn main() {
- loop {
- fuzz!(|data| {
- do_test(data);
- });
- }
-}
-
-#[cfg(all(test, fuzzing))]
-mod tests {
- fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
- let mut b = 0;
- for (idx, c) in hex.as_bytes().iter().enumerate() {
- b <<= 4;
- match *c {
- b'A'..=b'F' => b |= c - b'A' + 10,
- b'a'..=b'f' => b |= c - b'a' + 10,
- b'0'..=b'9' => b |= c - b'0',
- _ => panic!("Bad hex"),
- }
- if (idx & 1) == 1 {
- out.push(b);
- b = 0;
- }
- }
- }
+fuzz_target!(|data| {
+ do_test(data);
+});
- #[test]
- fn duplicate_crash() {
- let mut a = Vec::new();
- extend_vec_from_hex("0102030405", &mut a);
- super::do_test(&a);
- }
-}
diff --git a/fuzz/fuzz_targets/hashes/json.rs b/fuzz/fuzz_targets/hashes/json.rs
index 2513f2e2..3adfeba7 100644
--- a/fuzz/fuzz_targets/hashes/json.rs
+++ b/fuzz/fuzz_targets/hashes/json.rs
@@ -1,7 +1,11 @@
-use bitcoin::hashes::{ripemd160, sha1, sha256d, sha512, Hmac};
-use honggfuzz::fuzz;
+#![cfg_attr(fuzzing, no_main)]
+#![cfg_attr(not(fuzzing), allow(unused))]
+
+use libfuzzer_sys::fuzz_target;
use serde::{Deserialize, Serialize};
+use bitcoin::hashes::{ripemd160, sha1, sha256d, sha512, Hmac};
+
#[derive(Deserialize, Serialize)]
struct Hmacs {
sha1: Hmac<sha1::Hash>,
@@ -15,6 +19,9 @@ struct Main {
sha2d: sha256d::Hash,
}
+#[cfg(not(fuzzing))]
+fn main() {}
+
fn do_test(data: &[u8]) {
if let Ok(m) = serde_json::from_slice::<Main>(data) {
let vec = serde_json::to_vec(&m).unwrap();
@@ -22,35 +29,6 @@ fn do_test(data: &[u8]) {
}
}
-fn main() {
- loop {
- fuzz!(|d| { do_test(d) });
- }
-}
-
-#[cfg(all(test, fuzzing))]
-mod tests {
- fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
- let mut b = 0;
- for (idx, c) in hex.as_bytes().iter().enumerate() {
- b <<= 4;
- match *c {
- b'A'..=b'F' => b |= c - b'A' + 10,
- b'a'..=b'f' => b |= c - b'a' + 10,
- b'0'..=b'9' => b |= c - b'0',
- _ => panic!("Bad hex"),
- }
- if (idx & 1) == 1 {
- out.push(b);
- b = 0;
- }
- }
- }
-
- #[test]
- fn duplicate_crash() {
- let mut a = Vec::new();
- extend_vec_from_hex("00000", &mut a);
- super::do_test(&a);
- }
-}
+fuzz_target!(|data| {
+ do_test(data)
+});
diff --git a/fuzz/fuzz_targets/hashes/ripemd160.rs b/fuzz/fuzz_targets/hashes/ripemd160.rs
index a75ec547..a32cd948 100644
--- a/fuzz/fuzz_targets/hashes/ripemd160.rs
+++ b/fuzz/fuzz_targets/hashes/ripemd160.rs
@@ -1,5 +1,12 @@
+#![cfg_attr(fuzzing, no_main)]
+#![cfg_attr(not(fuzzing), allow(unused))]
+
+use libfuzzer_sys::fuzz_target;
+
use bitcoin::hashes::{ripemd160, HashEngine};
-use honggfuzz::fuzz;
+
+#[cfg(not(fuzzing))]
+fn main() {}
fn do_test(data: &[u8]) {
let mut engine = ripemd160::Hash::engine();
@@ -10,35 +17,6 @@ fn do_test(data: &[u8]) {
assert_eq!(hash.as_byte_array(), eng_hash.as_byte_array());
}
-fn main() {
- loop {
- fuzz!(|d| { do_test(d) });
- }
-}
-
-#[cfg(all(test, fuzzing))]
-mod tests {
- fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
- let mut b = 0;
- for (idx, c) in hex.as_bytes().iter().enumerate() {
- b <<= 4;
- match *c {
- b'A'..=b'F' => b |= c - b'A' + 10,
- b'a'..=b'f' => b |= c - b'a' + 10,
- b'0'..=b'9' => b |= c - b'0',
- _ => panic!("Bad hex"),
- }
- if (idx & 1) == 1 {
- out.push(b);
- b = 0;
- }
- }
- }
-
- #[test]
- fn duplicate_crash() {
- let mut a = Vec::new();
- extend_vec_from_hex("00000", &mut a);
- super::do_test(&a);
- }
-}
+fuzz_target!(|data| {
+ do_test(data)
+});
diff --git a/fuzz/fuzz_targets/hashes/sha1.rs b/fuzz/fuzz_targets/hashes/sha1.rs
index 0b9ab541..4f3a47da 100644
--- a/fuzz/fuzz_targets/hashes/sha1.rs
+++ b/fuzz/fuzz_targets/hashes/sha1.rs
@@ -1,5 +1,12 @@
+#![cfg_attr(fuzzing, no_main)]
+#![cfg_attr(not(fuzzing), allow(unused))]
+
+use libfuzzer_sys::fuzz_target;
+
use bitcoin::hashes::{sha1, HashEngine};
-use honggfuzz::fuzz;
+
+#[cfg(not(fuzzing))]
+fn main() {}
fn do_test(data: &[u8]) {
let mut engine = sha1::Hash::engine();
@@ -10,35 +17,6 @@ fn do_test(data: &[u8]) {
assert_eq!(hash.as_byte_array(), eng_hash.as_byte_array());
}
-fn main() {
- loop {
- fuzz!(|d| { do_test(d) });
- }
-}
-
-#[cfg(all(test, fuzzing))]
-mod tests {
- fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
- let mut b = 0;
- for (idx, c) in hex.as_bytes().iter().enumerate() {
- b <<= 4;
- match *c {
- b'A'..=b'F' => b |= c - b'A' + 10,
- b'a'..=b'f' => b |= c - b'a' + 10,
- b'0'..=b'9' => b |= c - b'0',
- _ => panic!("Bad hex"),
- }
- if (idx & 1) == 1 {
- out.push(b);
- b = 0;
- }
- }
- }
-
- #[test]
- fn duplicate_crash() {
- let mut a = Vec::new();
- extend_vec_from_hex("00000", &mut a);
- super::do_test(&a);
- }
-}
+fuzz_target!(|data| {
+ do_test(data)
+});
diff --git a/fuzz/fuzz_targets/hashes/sha256.rs b/fuzz/fuzz_targets/hashes/sha256.rs
index 57cb1a26..bb37386f 100644
--- a/fuzz/fuzz_targets/hashes/sha256.rs
+++ b/fuzz/fuzz_targets/hashes/sha256.rs
@@ -1,5 +1,12 @@
+#![cfg_attr(fuzzing, no_main)]
+#![cfg_attr(not(fuzzing), allow(unused))]
+
+use libfuzzer_sys::fuzz_target;
+
use bitcoin::hashes::{sha256, HashEngine};
-use honggfuzz::fuzz;
+
+#[cfg(not(fuzzing))]
+fn main() {}
fn do_test(data: &[u8]) {
let mut engine = sha256::Hash::engine();
@@ -10,35 +17,6 @@ fn do_test(data: &[u8]) {
assert_eq!(hash.as_byte_array(), eng_hash.as_byte_array());
}
-fn main() {
- loop {
- fuzz!(|d| { do_test(d) });
- }
-}
-
-#[cfg(all(test, fuzzing))]
-mod tests {
- fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
- let mut b = 0;
- for (idx, c) in hex.as_bytes().iter().enumerate() {
- b <<= 4;
- match *c {
- b'A'..=b'F' => b |= c - b'A' + 10,
- b'a'..=b'f' => b |= c - b'a' + 10,
- b'0'..=b'9' => b |= c - b'0',
- _ => panic!("Bad hex"),
- }
- if (idx & 1) == 1 {
- out.push(b);
- b = 0;
- }
- }
- }
-
- #[test]
- fn duplicate_crash() {
- let mut a = Vec::new();
- extend_vec_from_hex("fff400610004", &mut a);
- super::do_test(&a);
- }
-}
+fuzz_target!(|data| {
+ do_test(data)
+});
diff --git a/fuzz/fuzz_targets/hashes/sha512.rs b/fuzz/fuzz_targets/hashes/sha512.rs
index c5cd3e5e..f20a314e 100644
--- a/fuzz/fuzz_targets/hashes/sha512.rs
+++ b/fuzz/fuzz_targets/hashes/sha512.rs
@@ -1,5 +1,12 @@
+#![cfg_attr(fuzzing, no_main)]
+#![cfg_attr(not(fuzzing), allow(unused))]
+
+use libfuzzer_sys::fuzz_target;
+
use bitcoin::hashes::{sha512, HashEngine};
-use honggfuzz::fuzz;
+
+#[cfg(not(fuzzing))]
+fn main() {}
fn do_test(data: &[u8]) {
let mut engine = sha512::Hash::engine();
@@ -10,35 +17,6 @@ fn do_test(data: &[u8]) {
assert_eq!(hash.as_byte_array(), eng_hash.as_byte_array());
}
-fn main() {
- loop {
- fuzz!(|d| { do_test(d) });
- }
-}
-
-#[cfg(all(test, fuzzing))]
-mod tests {
- fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
- let mut b = 0;
- for (idx, c) in hex.as_bytes().iter().enumerate() {
- b <<= 4;
- match *c {
- b'A'..=b'F' => b |= c - b'A' + 10,
- b'a'..=b'f' => b |= c - b'a' + 10,
- b'0'..=b'9' => b |= c - b'0',
- _ => panic!("Bad hex"),
- }
- if (idx & 1) == 1 {
- out.push(b);
- b = 0;
- }
- }
- }
-
- #[test]
- fn duplicate_crash() {
- let mut a = Vec::new();
- extend_vec_from_hex("00000", &mut a);
- super::do_test(&a);
- }
-}
+fuzz_target!(|data| {
+ do_test(data)
+});
diff --git a/fuzz/fuzz_targets/hashes/sha512_256.rs b/fuzz/fuzz_targets/hashes/sha512_256.rs
index 60d85bec..4a3281f8 100644
--- a/fuzz/fuzz_targets/hashes/sha512_256.rs
+++ b/fuzz/fuzz_targets/hashes/sha512_256.rs
@@ -1,5 +1,12 @@
+#![cfg_attr(fuzzing, no_main)]
+#![cfg_attr(not(fuzzing), allow(unused))]
+
+use libfuzzer_sys::fuzz_target;
+
use bitcoin::hashes::{sha512_256, HashEngine};
-use honggfuzz::fuzz;
+
+#[cfg(not(fuzzing))]
+fn main() {}
fn do_test(data: &[u8]) {
let mut engine = sha512_256::Hash::engine();
@@ -10,35 +17,6 @@ fn do_test(data: &[u8]) {
assert_eq!(hash.as_byte_array(), eng_hash.as_byte_array());
}
-fn main() {
- loop {
- fuzz!(|d| { do_test(d) });
- }
-}
-
-#[cfg(all(test, fuzzing))]
-mod tests {
- fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
- let mut b = 0;
- for (idx, c) in hex.as_bytes().iter().enumerate() {
- b <<= 4;
- match *c {
- b'A'..=b'F' => b |= c - b'A' + 10,
- b'a'..=b'f' => b |= c - b'a' + 10,
- b'0'..=b'9' => b |= c - b'0',
- _ => panic!("Bad hex"),
- }
- if (idx & 1) == 1 {
- out.push(b);
- b = 0;
- }
- }
- }
-
- #[test]
- fn duplicate_crash() {
- let mut a = Vec::new();
- extend_vec_from_hex("00000", &mut a);
- super::do_test(&a);
- }
-}
+fuzz_target!(|data| {
+ do_test(data)
+});
diff --git a/fuzz/fuzz_targets/p2p/arbitrary_addrv2.rs b/fuzz/fuzz_targets/p2p/arbitrary_addrv2.rs
index 31f4fa56..9d0ef689 100644
--- a/fuzz/fuzz_targets/p2p/arbitrary_addrv2.rs
+++ b/fuzz/fuzz_targets/p2p/arbitrary_addrv2.rs
@@ -1,10 +1,17 @@
+#![cfg_attr(fuzzing, no_main)]
+#![cfg_attr(not(fuzzing), allow(unused))]
+
+use libfuzzer_sys::fuzz_target;
+
+use arbitrary::{Arbitrary, Unstructured};
use std::convert::TryFrom;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
-use arbitrary::{Arbitrary, Unstructured};
-use honggfuzz::fuzz;
use p2p::address::AddrV2;
+#[cfg(not(fuzzing))]
+fn main() {}
+
fn do_test(data: &[u8]) {
let mut u = Unstructured::new(data);
let a = AddrV2::arbitrary(&mut u);
@@ -36,37 +43,6 @@ fn do_test(data: &[u8]) {
}
}
-fn main() {
- loop {
- fuzz!(|data| {
- do_test(data);
- });
- }
-}
-
-#[cfg(all(test, fuzzing))]
-mod tests {
- fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
- let mut b = 0;
- for (idx, c) in hex.as_bytes().iter().enumerate() {
- b <<= 4;
- match *c {
- b'A'..=b'F' => b |= c - b'A' + 10,
- b'a'..=b'f' => b |= c - b'a' + 10,
- b'0'..=b'9' => b |= c - b'0',
- _ => panic!("Bad hex"),
- }
- if (idx & 1) == 1 {
- out.push(b);
- b = 0;
- }
- }
- }
-
- #[test]
- fn duplicate_crash() {
- let mut a = Vec::new();
- extend_vec_from_hex("00", &mut a);
- super::do_test(&a);
- }
-}
+fuzz_target!(|data| {
+ do_test(data);
+});
diff --git a/fuzz/fuzz_targets/p2p/deserialize_addrv2.rs b/fuzz/fuzz_targets/p2p/deserialize_addrv2.rs
index 6f4577dc..5b89442f 100644
--- a/fuzz/fuzz_targets/p2p/deserialize_addrv2.rs
+++ b/fuzz/fuzz_targets/p2p/deserialize_addrv2.rs
@@ -1,40 +1,15 @@
-use honggfuzz::fuzz;
+#![cfg_attr(fuzzing, no_main)]
+#![cfg_attr(not(fuzzing), allow(unused))]
+
+use libfuzzer_sys::fuzz_target;
+
+#[cfg(not(fuzzing))]
+fn main() {}
fn do_test(data: &[u8]) {
let _: Result<p2p::address::AddrV2, _> = bitcoin::consensus::encode::deserialize(data);
}
-fn main() {
- loop {
- fuzz!(|data| {
- do_test(data);
- });
- }
-}
-
-#[cfg(all(test, fuzzing))]
-mod tests {
- fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
- let mut b = 0;
- for (idx, c) in hex.as_bytes().iter().enumerate() {
- b <<= 4;
- match *c {
- b'A'..=b'F' => b |= c - b'A' + 10,
- b'a'..=b'f' => b |= c - b'a' + 10,
- b'0'..=b'9' => b |= c - b'0',
- _ => panic!("Bad hex"),
- }
- if (idx & 1) == 1 {
- out.push(b);
- b = 0;
- }
- }
- }
-
- #[test]
- fn duplicate_crash() {
- let mut a = Vec::new();
- extend_vec_from_hex("00", &mut a);
- super::do_test(&a);
- }
-}
+fuzz_target!(|data| {
+ do_test(data);
+});
diff --git a/fuzz/fuzz_targets/p2p/deserialize_raw_net_msg.rs b/fuzz/fuzz_targets/p2p/deserialize_raw_net_msg.rs
index f21830bd..7e5ad13a 100644
--- a/fuzz/fuzz_targets/p2p/deserialize_raw_net_msg.rs
+++ b/fuzz/fuzz_targets/p2p/deserialize_raw_net_msg.rs
@@ -1,41 +1,16 @@
-use honggfuzz::fuzz;
+#![cfg_attr(fuzzing, no_main)]
+#![cfg_attr(not(fuzzing), allow(unused))]
+
+use libfuzzer_sys::fuzz_target;
+
+#[cfg(not(fuzzing))]
+fn main() {}
fn do_test(data: &[u8]) {
let _: Result<p2p::message::V1NetworkMessage, _> =
bitcoin::consensus::encode::deserialize(data);
}
-fn main() {
- loop {
- fuzz!(|data| {
- do_test(data);
- });
- }
-}
-
-#[cfg(all(test, fuzzing))]
-mod tests {
- fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
- let mut b = 0;
- for (idx, c) in hex.as_bytes().iter().enumerate() {
- b <<= 4;
- match *c {
- b'A'..=b'F' => b |= c - b'A' + 10,
- b'a'..=b'f' => b |= c - b'a' + 10,
- b'0'..=b'9' => b |= c - b'0',
- _ => panic!("Bad hex"),
- }
- if (idx & 1) == 1 {
- out.push(b);
- b = 0;
- }
- }
- }
-
- #[test]
- fn duplicate_crash() {
- let mut a = Vec::new();
- extend_vec_from_hex("00", &mut a);
- super::do_test(&a);
- }
-}
+fuzz_target!(|data| {
+ do_test(data);
+});
diff --git a/fuzz/fuzz_targets/units/arbitrary_weight.rs b/fuzz/fuzz_targets/units/arbitrary_weight.rs
index 93ce2d82..acf9b2e2 100644
--- a/fuzz/fuzz_targets/units/arbitrary_weight.rs
+++ b/fuzz/fuzz_targets/units/arbitrary_weight.rs
@@ -1,6 +1,13 @@
+#![cfg_attr(fuzzing, no_main)]
+#![cfg_attr(not(fuzzing), allow(unused))]
+
+use libfuzzer_sys::fuzz_target;
use arbitrary::{Arbitrary, Unstructured};
+
use bitcoin::Weight;
-use honggfuzz::fuzz;
+
+#[cfg(not(fuzzing))]
+fn main() {}
fn do_test(data: &[u8]) {
let mut u = Unstructured::new(data);
@@ -51,37 +58,6 @@ fn do_test(data: &[u8]) {
}
}
-fn main() {
- loop {
- fuzz!(|data| {
- do_test(data);
- });
- }
-}
-
-#[cfg(all(test, fuzzing))]
-mod tests {
- fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
- let mut b = 0;
- for (idx, c) in hex.as_bytes().iter().enumerate() {
- b <<= 4;
- match *c {
- b'A'..=b'F' => b |= c - b'A' + 10,
- b'a'..=b'f' => b |= c - b'a' + 10,
- b'0'..=b'9' => b |= c - b'0',
- _ => panic!("Bad hex"),
- }
- if (idx & 1) == 1 {
- out.push(b);
- b = 0;
- }
- }
- }
-
- #[test]
- fn duplicate_crash() {
- let mut a = Vec::new();
- extend_vec_from_hex("00", &mut a);
- super::do_test(&a);
- }
-}
+fuzz_target!(|data| {
+ do_test(data);
+});
diff --git a/fuzz/fuzz_targets/units/parse_amount.rs b/fuzz/fuzz_targets/units/parse_amount.rs
index 61553a3d..a6f15714 100644
--- a/fuzz/fuzz_targets/units/parse_amount.rs
+++ b/fuzz/fuzz_targets/units/parse_amount.rs
@@ -1,4 +1,10 @@
-use honggfuzz::fuzz;
+#![cfg_attr(fuzzing, no_main)]
+#![cfg_attr(not(fuzzing), allow(unused))]
+
+use libfuzzer_sys::fuzz_target;
+
+#[cfg(not(fuzzing))]
+fn main() {}
fn do_test(data: &[u8]) {
let data_str = String::from_utf8_lossy(data);
@@ -26,37 +32,6 @@ fn do_test(data: &[u8]) {
assert_eq!(amt, amt_roundtrip);
}
-fn main() {
- loop {
- fuzz!(|data| {
- do_test(data);
- });
- }
-}
-
-#[cfg(all(test, fuzzing))]
-mod tests {
- fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
- let mut b = 0;
- for (idx, c) in hex.as_bytes().iter().enumerate() {
- b <<= 4;
- match *c {
- b'A'..=b'F' => b |= c - b'A' + 10,
- b'a'..=b'f' => b |= c - b'a' + 10,
- b'0'..=b'9' => b |= c - b'0',
- _ => panic!("Bad hex"),
- }
- if (idx & 1) == 1 {
- out.push(b);
- b = 0;
- }
- }
- }
-
- #[test]
- fn duplicate_crash() {
- let mut a = Vec::new();
- extend_vec_from_hex("00000000", &mut a);
- super::do_test(&a);
- }
-}
+fuzz_target!(|data| {
+ do_test(data);
+});
diff --git a/fuzz/fuzz_targets/units/parse_int.rs b/fuzz/fuzz_targets/units/parse_int.rs
index 7d3e826f..9b422cef 100644
--- a/fuzz/fuzz_targets/units/parse_int.rs
+++ b/fuzz/fuzz_targets/units/parse_int.rs
@@ -1,6 +1,13 @@
+#![cfg_attr(fuzzing, no_main)]
+#![cfg_attr(not(fuzzing), allow(unused))]
+
+use libfuzzer_sys::fuzz_target;
use arbitrary::Unstructured;
+
use bitcoin::parse_int;
-use honggfuzz::fuzz;
+
+#[cfg(not(fuzzing))]
+fn main() {}
fn do_test(data: &[u8]) {
let mut u = Unstructured::new(data);
@@ -70,37 +77,6 @@ fn do_test(data: &[u8]) {
}
}
-fn main() {
- loop {
- fuzz!(|data| {
- do_test(data);
- });
- }
-}
-
-#[cfg(all(test, fuzzing))]
-mod tests {
- fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
- let mut b = 0;
- for (idx, c) in hex.as_bytes().iter().enumerate() {
- b <<= 4;
- match *c {
- b'A'..=b'F' => b |= c - b'A' + 10,
- b'a'..=b'f' => b |= c - b'a' + 10,
- b'0'..=b'9' => b |= c - b'0',
- _ => panic!("Bad hex"),
- }
- if (idx & 1) == 1 {
- out.push(b);
- b = 0;
- }
- }
- }
-
- #[test]
- fn duplicate_crash() {
- let mut a = Vec::new();
- extend_vec_from_hex("00", &mut a);
- super::do_test(&a);
- }
-}
+fuzz_target!(|data| {
+ do_test(data);
+});
diff --git a/fuzz/fuzz_targets/units/standard_checks.rs b/fuzz/fuzz_targets/units/standard_checks.rs
index 24b1c917..85d60a6b 100644
--- a/fuzz/fuzz_targets/units/standard_checks.rs
+++ b/fuzz/fuzz_targets/units/standard_checks.rs
@@ -1,10 +1,13 @@
-use bitcoin::absolute::{Height, MedianTimePast};
-use bitcoin::relative::{NumberOf512Seconds, NumberOfBlocks};
+#![cfg_attr(fuzzing, no_main)]
+#![cfg_attr(not(fuzzing), allow(unused))]
+
+use libfuzzer_sys::fuzz_target;
use bitcoin::{
Amount, BlockHeight, BlockHeightInterval, BlockMtp, BlockMtpInterval, BlockTime, FeeRate,
Sequence, SignedAmount, Weight,
};
-use honggfuzz::fuzz;
+use bitcoin::absolute::{Height, MedianTimePast};
+use bitcoin::relative::{NumberOf512Seconds, NumberOfBlocks};
use standard_test::StandardChecks as _;
/// Implements the traits on the wrapper type $ty. Intended only to be called from inside wrap_for_checks!
@@ -68,6 +71,9 @@ mod fuzz {
wrap_for_checks!(Weight, super::Weight::MIN_TRANSACTION);
}
+#[cfg(not(fuzzing))]
+fn main() {}
+
fn do_test(data: &[u8]) {
fuzz::Amount::one_iteration(data);
fuzz::BlockHeight::one_iteration(data);
@@ -85,37 +91,6 @@ fn do_test(data: &[u8]) {
fuzz::Weight::one_iteration(data);
}
-fn main() {
- loop {
- fuzz!(|data| {
- do_test(data);
- });
- }
-}
-
-#[cfg(all(test, fuzzing))]
-mod tests {
- fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
- let mut b = 0;
- for (idx, c) in hex.as_bytes().iter().enumerate() {
- b <<= 4;
- match *c {
- b'A'..=b'F' => b |= c - b'A' + 10,
- b'a'..=b'f' => b |= c - b'a' + 10,
- b'0'..=b'9' => b |= c - b'0',
- _ => panic!("Bad hex"),
- }
- if (idx & 1) == 1 {
- out.push(b);
- b = 0;
- }
- }
- }
-
- #[test]
- fn duplicate_crash() {
- let mut a = Vec::new();
- extend_vec_from_hex("00000000", &mut a);
- super::do_test(&a);
- }
-}
+fuzz_target!(|data| {
+ do_test(data);
+});
diff --git a/fuzz/generate-files.sh b/fuzz/generate-files.sh
index 4d438237..ec03349a 100755
--- a/fuzz/generate-files.sh
+++ b/fuzz/generate-files.sh
@@ -22,12 +22,12 @@ publish = false
cargo-fuzz = true
[dependencies]
-honggfuzz = { version = "0.5.58", default-features = false }
bitcoin = { path = "../bitcoin", features = [ "serde", "arbitrary" ] }
-p2p = { path = "../p2p", package = "bitcoin-p2p-messages", features = ["arbitrary"] }
bitcoin_consensus_encoding = { path = "../consensus_encoding", package = "bitcoin-consensus-encoding" }
-arbitrary = { version = "1.4.1" }
+p2p = { path = "../p2p", package = "bitcoin-p2p-messages", features = ["arbitrary"] }
+arbitrary = { version = "1.4.1" }
+libfuzzer-sys = { version = "0.4.0" }
serde = { version = "1.0.195", features = [ "derive" ] }
serde_json = "1.0.68"
standard_test = "0.1.0"
@@ -47,6 +47,9 @@ for targetFile in $(listTargetFiles); do
[[bin]]
name = "$targetName"
path = "$targetFile"
+test = false
+doc = false
+bench = false
EOF
done
@@ -75,7 +78,7 @@ jobs:
# We only get 20 jobs at a time, we probably don't want to go
# over that limit with fuzzing because of the hour run time.
fuzz_target: [
-$(for name in $(listTargetNames); do echo " $name,"; done)
+$(for name in $(cargo fuzz list); do echo " $name,"; done)
]
steps:
- name: Install test dependencies
@@ -84,7 +87,6 @@ $(for name in $(listTargetNames); do echo " $name,"; done)
with:
persist-credentials: false
- uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
-
id: cache-fuzz
with:
path: |
@@ -122,6 +124,6 @@ $(for name in $(listTargetNames); do echo " $name,"; done)
- name: Display structure of downloaded files
run: ls -R
- run: find executed_* -type f -exec cat {} + | sort > executed
- - run: source ./fuzz/fuzz-util.sh && listTargetNames | sort | diff - executed
+ - run: cargo fuzz list | sort | diff - executed
EOF
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.