Skip to content

Commit eab585e

Browse files
authored
Add fuzzing for Validator::validate (#7)
1 parent 7906e2a commit eab585e

File tree

4 files changed

+51
-0
lines changed

4 files changed

+51
-0
lines changed

fuzz/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ cargo-fuzz = true
1111

1212
[dependencies]
1313
libfuzzer-sys = "0.3.1"
14+
serde_json = "1.0"
1415

1516
[dependencies.jtd]
1617
path = ".."
@@ -23,3 +24,7 @@ members = ["."]
2324
[[bin]]
2425
name = "serde_schema_try_into"
2526
path = "fuzz_targets/serde_schema_try_into.rs"
27+
28+
[[bin]]
29+
name = "validate"
30+
path = "fuzz_targets/validate.rs"

fuzz/fuzz_targets/validate.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#![no_main]
2+
use libfuzzer_sys::fuzz_target;
3+
4+
use serde_json;
5+
6+
fuzz_target!(|schema_and_instance: (jtd::schema::Schema, Vec<u8>)| {
7+
let validator = jtd::validator::Validator {
8+
max_errors: None,
9+
max_depth: None,
10+
};
11+
12+
// We're only interested in fuzzing against valid schemas.
13+
if schema_and_instance.0.validate().is_err() {
14+
return;
15+
}
16+
17+
if let Ok(instance) = serde_json::from_slice(&schema_and_instance.1) {
18+
let _ = validator.validate(&schema_and_instance.0, &instance);
19+
}
20+
});

src/form.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::collections::HashSet;
44
use std::str::FromStr;
55

66
#[derive(Debug, PartialEq)]
7+
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
78
pub enum Form {
89
Empty,
910
Ref(Ref),
@@ -22,18 +23,21 @@ impl Default for Form {
2223
}
2324

2425
#[derive(Debug, PartialEq)]
26+
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
2527
pub struct Ref {
2628
pub nullable: bool,
2729
pub definition: String,
2830
}
2931

3032
#[derive(Debug, PartialEq)]
33+
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
3134
pub struct Type {
3235
pub nullable: bool,
3336
pub type_value: TypeValue,
3437
}
3538

3639
#[derive(Debug, PartialEq)]
40+
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
3741
pub enum TypeValue {
3842
Boolean,
3943
Float32,
@@ -70,18 +74,21 @@ impl FromStr for TypeValue {
7074
}
7175

7276
#[derive(Debug, PartialEq)]
77+
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
7378
pub struct Enum {
7479
pub nullable: bool,
7580
pub values: HashSet<String>,
7681
}
7782

7883
#[derive(Debug, PartialEq)]
84+
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
7985
pub struct Elements {
8086
pub nullable: bool,
8187
pub schema: Box<Schema>,
8288
}
8389

8490
#[derive(Debug, PartialEq)]
91+
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
8592
pub struct Properties {
8693
pub nullable: bool,
8794
pub required: HashMap<String, Schema>,
@@ -91,12 +98,14 @@ pub struct Properties {
9198
}
9299

93100
#[derive(Debug, PartialEq)]
101+
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
94102
pub struct Values {
95103
pub nullable: bool,
96104
pub schema: Box<Schema>,
97105
}
98106

99107
#[derive(Debug, PartialEq)]
108+
#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
100109
pub struct Discriminator {
101110
pub nullable: bool,
102111
pub discriminator: String,

src/schema.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,23 @@ pub struct Schema {
1111
pub metadata: HashMap<String, Value>,
1212
}
1313

14+
#[cfg(feature = "fuzz")]
15+
impl arbitrary::Arbitrary for Schema {
16+
fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
17+
Ok(Schema {
18+
definitions: arbitrary::Arbitrary::arbitrary(u)?,
19+
form: arbitrary::Arbitrary::arbitrary(u)?,
20+
21+
// serde_json::Value does not derive Arbitrary. That's ok, because
22+
// for the fuzz tests we're doing, we don't really care about
23+
// manipulating arbitrary JSON values.
24+
//
25+
// So we'll always have metadata be None.
26+
metadata: HashMap::new(),
27+
})
28+
}
29+
}
30+
1431
#[derive(Debug, PartialEq)]
1532
pub enum SerdeConvertError {
1633
InvalidForm,

0 commit comments

Comments
 (0)