Skip to content

Commit f598c47

Browse files
committed
Merge BlockstreamResearch#162: fix broken fuzz target compile_parse_tree
445ae20 add `fuzz` to the workspace members table (Lucas Balieiro) 5ad664a fuzz: align `fuzz_targets` to follow the `rust-simplicity` style (Lucas Balieiro) f51d91f add CI job that `cargo check` the fuzz crate (Lucas Balieiro) 0760378 fix fuzz target `compile_parse_tree` (Lucas Balieiro) Pull request description: closes BlockstreamResearch#161 updates the outdated fuzz target `compile_parse_tree`. It was still using `named::to_commit_node`, which has since been replaced by `named::forget_names` (see [this commit](BlockstreamResearch@7150f0e)) Also (as suggested in the issue discussion): * removed `fuzz` from the exclude list in `Cargo.toml` and add to workspace members * added a CI job to `cargo check` the fuzz crate ACKs for top commit: apoelstra: ACK 445ae20; successfully ran local tests Tree-SHA512: bbc10ef2340515973d2083c6fff608978ed7cc3cd559b1c0161ac6a2d660079fadd6687244b1892ae7505ba1c0bc7b1c5c17c1bd44305791ae52bf6b10463e5f
2 parents 5c250a4 + 445ae20 commit f598c47

File tree

11 files changed

+259
-51
lines changed

11 files changed

+259
-51
lines changed

.github/workflows/rust.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,3 +169,23 @@ jobs:
169169
uses: dtolnay/rust-toolchain@stable
170170
- run: rustup target add wasm32-unknown-unknown
171171
- run: cargo check --target wasm32-unknown-unknown
172+
173+
Fuzz:
174+
name: Check Fuzz
175+
needs: Prepare
176+
runs-on: ubuntu-latest
177+
strategy:
178+
fail-fast: false
179+
steps:
180+
- name: "Checkout repo"
181+
uses: actions/checkout@v4
182+
183+
- name: "Select nightly toolchain"
184+
uses: dtolnay/rust-toolchain@v1
185+
with:
186+
toolchain: ${{ needs.Prepare.outputs.nightly_version }}
187+
188+
- name: "Check fuzz crate"
189+
run: |
190+
cargo check --manifest-path=fuzz/Cargo.toml
191+

Cargo.lock

Lines changed: 39 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ clap = "4.5.37"
3838
getrandom = { version = "0.2", features = ["js"] }
3939

4040
[workspace]
41-
members = ["codegen"]
42-
exclude = ["fuzz", "bitcoind-tests"]
41+
members = ["codegen", "fuzz"]
42+
exclude = ["bitcoind-tests"]
4343

4444
[lints.clippy]
4545
# Exclude lints we don't think are valuable.

fuzz/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ simplicityhl = { path = "..", features = ["arbitrary", "serde"] }
1414
itertools = "0.13.0"
1515
serde_json = "1.0.105"
1616

17+
[dev-dependencies]
18+
base64 = "0.22.1"
19+
20+
[lints.rust]
21+
unexpected_cfgs = { level = "deny", check-cfg = ['cfg(fuzzing)'] }
22+
1723
[[bin]]
1824
name = "compile_text"
1925
path = "fuzz_targets/compile_text.rs"

fuzz/fuzz_targets/compile_parse_tree.rs

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
#![no_main]
1+
#![cfg_attr(fuzzing, no_main)]
22

3-
use arbitrary::Arbitrary;
4-
use libfuzzer_sys::fuzz_target;
3+
#[cfg(any(fuzzing, test))]
4+
fn do_test(data: &[u8]) {
5+
use arbitrary::Arbitrary;
56

6-
use simplicityhl::error::WithFile;
7-
use simplicityhl::{ast, named, parse, ArbitraryOfType, Arguments};
7+
use simplicityhl::error::WithFile;
8+
use simplicityhl::{ast, named, parse, ArbitraryOfType, Arguments};
89

9-
fuzz_target!(|data: &[u8]| {
1010
let mut u = arbitrary::Unstructured::new(data);
1111
let parse_program = match parse::Program::arbitrary(&mut u) {
1212
Ok(x) => x,
@@ -24,6 +24,24 @@ fuzz_target!(|data: &[u8]| {
2424
.compile(arguments, false)
2525
.with_file("")
2626
.expect("AST should compile with given arguments");
27-
let _simplicity_commit = named::to_commit_node(&simplicity_named_construct)
28-
.expect("Conversion to commit node should never fail");
29-
});
27+
let _simplicity_commit = named::forget_names(&simplicity_named_construct);
28+
}
29+
30+
#[cfg(fuzzing)]
31+
libfuzzer_sys::fuzz_target!(|data| do_test(data));
32+
33+
#[cfg(not(fuzzing))]
34+
fn main() {}
35+
36+
#[cfg(test)]
37+
mod tests {
38+
use base64::Engine;
39+
40+
#[test]
41+
fn duplicate_crash() {
42+
let data = base64::prelude::BASE64_STANDARD
43+
.decode("Cg==")
44+
.expect("base64 should be valid");
45+
super::do_test(&data);
46+
}
47+
}

fuzz/fuzz_targets/compile_text.rs

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
1-
#![no_main]
2-
3-
use arbitrary::Arbitrary;
4-
use libfuzzer_sys::{fuzz_target, Corpus};
5-
6-
use simplicityhl::{ArbitraryOfType, Arguments};
1+
#![cfg_attr(fuzzing, no_main)]
72

83
/// The PEST parser is slow for inputs with many open brackets.
94
/// Detect some of these inputs to reject them from the corpus.
105
///
116
/// ```text
127
/// fn n(){ { (s,(( (Ns,(s,(x,(((s,((s,(s,(s,(x,(( {5
138
/// ```
9+
#[cfg(any(fuzzing, test))]
1410
fn slow_input(program_text: &str) -> bool {
1511
let mut consecutive_open_brackets = 0;
1612

@@ -28,7 +24,12 @@ fn slow_input(program_text: &str) -> bool {
2824
false
2925
}
3026

31-
fuzz_target!(|data: &[u8]| -> Corpus {
27+
#[cfg(any(fuzzing, test))]
28+
fn do_test(data: &[u8]) -> libfuzzer_sys::Corpus {
29+
use arbitrary::Arbitrary;
30+
use libfuzzer_sys::Corpus;
31+
use simplicityhl::{ArbitraryOfType, Arguments};
32+
3233
let mut u = arbitrary::Unstructured::new(data);
3334

3435
let program_text = match <String>::arbitrary(&mut u) {
@@ -49,4 +50,25 @@ fuzz_target!(|data: &[u8]| -> Corpus {
4950
let _ = template.instantiate(arguments, false);
5051

5152
Corpus::Keep
53+
}
54+
55+
#[cfg(fuzzing)]
56+
libfuzzer_sys::fuzz_target!(|data: &[u8]| {
57+
let _ = do_test(data);
5258
});
59+
60+
#[cfg(not(fuzzing))]
61+
fn main() {}
62+
63+
#[cfg(test)]
64+
mod tests {
65+
use base64::Engine;
66+
67+
#[test]
68+
fn duplicate_crash() {
69+
let data = base64::prelude::BASE64_STANDARD
70+
.decode("Cg==")
71+
.expect("base64 should be valid");
72+
super::do_test(&data);
73+
}
74+
}
Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,38 @@
1-
#![no_main]
1+
#![cfg_attr(fuzzing, no_main)]
22

3-
use libfuzzer_sys::fuzz_target;
3+
#[cfg(any(fuzzing, test))]
4+
fn do_test(parse_program: simplicityhl::parse::Program) {
5+
use simplicityhl::parse::{ParseFromStr, Program};
46

5-
use simplicityhl::parse::{self, ParseFromStr};
6-
7-
fuzz_target!(|parse_program: parse::Program| {
87
let program_text = parse_program.to_string();
9-
let restored_parse_program = parse::Program::parse_from_str(program_text.as_str())
8+
let restored_parse_program = Program::parse_from_str(program_text.as_str())
109
.expect("Output of fmt::Display should be parseable");
1110
assert_eq!(
1211
parse_program, restored_parse_program,
1312
"Output of fmt::Display should parse to original program"
1413
);
14+
}
15+
16+
#[cfg(not(fuzzing))]
17+
fn main() {}
18+
19+
#[cfg(fuzzing)]
20+
libfuzzer_sys::fuzz_target!(|data: simplicityhl::parse::Program| {
21+
do_test(data);
1522
});
23+
24+
#[cfg(test)]
25+
mod test {
26+
27+
use simplicityhl::parse::{ParseFromStr, Program};
28+
#[test]
29+
fn test() {
30+
let program_test = r#"fn main() {
31+
assert!(jet::eq_32(witness::A, witness::A));
32+
}"#;
33+
34+
let program = Program::parse_from_str(program_test)
35+
.expect("expected conversion to Program to be successfull");
36+
super::do_test(program);
37+
}
38+
}
Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,36 @@
1-
#![no_main]
1+
#![cfg_attr(fuzzing, no_main)]
22

3-
use libfuzzer_sys::fuzz_target;
3+
#[cfg(any(fuzzing, test))]
4+
fn do_test(value: simplicityhl::value::Value) {
5+
use simplicityhl::value::Value;
46

5-
use simplicityhl::value::Value;
6-
7-
fuzz_target!(|value: Value| {
87
let value_string = value.to_string();
98
let parsed_value =
109
Value::parse_from_str(&value_string, value.ty()).expect("Value string should be parseable");
1110
assert_eq!(
1211
value, parsed_value,
1312
"Value string should parse to original value"
1413
);
14+
}
15+
16+
#[cfg(not(fuzzing))]
17+
fn main() {}
18+
19+
#[cfg(fuzzing)]
20+
libfuzzer_sys::fuzz_target!(|data: simplicityhl::value::Value| {
21+
do_test(data);
1522
});
23+
24+
#[cfg(test)]
25+
mod test {
26+
use simplicityhl::{types::TypeConstructible, value::Value, ResolvedType};
27+
28+
use crate::do_test;
29+
#[test]
30+
fn test() {
31+
let value = Value::parse_from_str("true", &ResolvedType::boolean())
32+
.expect("should parse a valid value");
33+
34+
do_test(value);
35+
}
36+
}
Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
#![no_main]
1+
#![cfg_attr(fuzzing, no_main)]
22

3-
use libfuzzer_sys::fuzz_target;
4-
5-
use simplicityhl::WitnessValues;
6-
7-
fuzz_target!(|witness_values: WitnessValues| {
3+
#[cfg(any(fuzzing, test))]
4+
fn do_test(witness_values: simplicityhl::WitnessValues) {
85
let witness_text = serde_json::to_string(&witness_values)
96
.expect("Witness map should be convertible into JSON");
107
let parsed_witness_text =
@@ -13,4 +10,27 @@ fuzz_target!(|witness_values: WitnessValues| {
1310
witness_values, parsed_witness_text,
1411
"Witness JSON should parse to original witness map"
1512
);
16-
});
13+
}
14+
15+
#[cfg(not(fuzzing))]
16+
fn main() {}
17+
18+
#[cfg(fuzzing)]
19+
libfuzzer_sys::fuzz_target!(|data: simplicityhl::WitnessValues| do_test(data));
20+
21+
#[cfg(test)]
22+
mod test {
23+
use simplicityhl::{parse::ParseFromStr, WitnessValues};
24+
#[test]
25+
fn test() {
26+
let witness_text = r#"mod witness {
27+
const A: u32 = 1;
28+
const B: u32 = 2;
29+
const C: u32 = 3;
30+
}"#;
31+
32+
let witness_values = WitnessValues::parse_from_str(witness_text)
33+
.expect("parsing of valid string should work");
34+
super::do_test(witness_values);
35+
}
36+
}

0 commit comments

Comments
 (0)