Skip to content

Commit

Permalink
tests(fuzz): Add parse_date fuzzing target (#1127)
Browse files Browse the repository at this point in the history
Add a fuzzing target for parsing into a Timestamp and comparing the result with crate chrono.
  • Loading branch information
caspermeijn committed Aug 17, 2024
1 parent 409b932 commit df3e58e
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 0 deletions.
9 changes: 9 additions & 0 deletions fuzz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ cargo-fuzz = true
libfuzzer-sys = "0.4"
tests = { path = "../tests" }
protobuf = { path = "../protobuf" }
prost-types = { path = "../prost-types" }
chrono = "0.4"

[[bin]]
name = "proto3"
Expand All @@ -26,3 +28,10 @@ path = "fuzzers/proto2.rs"
test = false
doc = false
bench = false

[[bin]]
name = "parse_date"
path = "fuzzers/parse_date.rs"
test = false
doc = false
bench = false
49 changes: 49 additions & 0 deletions fuzz/fuzzers/parse_date.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#![no_main]

use libfuzzer_sys::fuzz_target;

fuzz_target!(|data: &[u8]| test_parse_date(data));

fn test_parse_date(data: &[u8]) {
use std::str::from_utf8;
use std::str::FromStr;

// input must be text
let Ok(original_text) = from_utf8(data) else {
return;
};

// parse input as a datetime
let Ok(timestamp) = prost_types::Timestamp::from_str(original_text) else {
let chrono_parse = chrono::DateTime::parse_from_rfc3339(original_text);
assert!(
chrono_parse.is_err(),
"prost failed to parse time, but chrono does parse this time: {}",
original_text
);
return;
};

// roundtrip to and from string
let roundtrip_text = format!("{timestamp}");
assert_eq!(Ok(&timestamp), roundtrip_text.parse().as_ref());

// chrono can only parse year 0000 till 9999
if let Ok(chrono_time) = chrono::DateTime::parse_from_rfc3339(original_text) {
if chrono_time.timestamp_subsec_nanos() > 999_999_999 {
// prost ignores leap seconds, but chrono increases the nanos in that case
return;
}

assert_eq!(timestamp.seconds, chrono_time.timestamp());
assert_eq!(timestamp.nanos, chrono_time.timestamp_subsec_nanos() as i32);

// roundtrip using chrono
let chrono_text = chrono_time.to_utc().to_rfc3339();
assert_eq!(
roundtrip_text.strip_suffix("Z").unwrap(),
chrono_text.strip_suffix("+00:00").unwrap()
);
assert_eq!(Ok(&timestamp), chrono_text.parse().as_ref());
}
}

0 comments on commit df3e58e

Please sign in to comment.