Add fuzzing harness for ISO-8601 related functions.
Testing this PR
Run:
$ CC=clang CXX=clang++ ./configure --enable-fuzz \
--with-sanitizers=address,fuzzer,undefined
$ make
$ src/test/fuzz/parse_iso8601
…
Add fuzzing harness for ISO-8601 related functions.
Testing this PR
Run:
$ CC=clang CXX=clang++ ./configure --enable-fuzz \
--with-sanitizers=address,fuzzer,undefined
$ make
$ src/test/fuzz/parse_iso8601
…
<!--e57a25ab6845829454e8d69fc972939a-->
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.
<!--174a7506f384e20aa4161008e828411d-->
Reviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.
Concept ACK :smile:
20 | + 21 | + const std::string iso8601_datetime = FormatISO8601DateTime(random_time); 22 | + const int64_t parsed_time_1 = ParseISO8601DateTime(iso8601_datetime); 23 | + if (random_time >= 0) { 24 | + assert(parsed_time_1 >= 0); 25 | + if (iso8601_datetime.length() == 20) {
can you explain the rational for this if? shouldn't it always be 20?
Unfortunately not:
$ FormatISO8601DateTime(std::numeric_limits<int64_t>::min())
-219246529--2134443519-00T08:29:52Z
$ FormatISO8601DateTime(0)
1970-01-01T00:00:00Z
$ FormatISO8601DateTime(std::numeric_limits<int64_t>::max())
219250468--2134443519-00T15:30:07Z
Thus we're only expecting the round-trip to work in the 20 char case :)
what the heck is that :O
Concept ACK.
Though it might also be nice to fuzz them separately. (specifically the Parse function).
Because if Format works correctly than parse here is always checked under sunny day scenario.
EDIT: You already do that :)
11 | @@ -12,6 +12,10 @@ 12 | import subprocess 13 | import logging 14 | 15 | +# Fuzzers known to lack a seed corpus in https://github.com/bitcoin-core/qa-assets/tree/master/fuzz_seed_corpus 16 | +FUZZERS_MISSING_CORPORA = [ 17 | + "parse_iso8601", 18 | +]
Can remove this?
Also: (I know it is not related to this pull request), but could you please add undefined to --with-sanitizers=fuzzer,address in the doc/fuzzing.md readme?
btw, the seeds look rather boring this time: https://github.com/bitcoin-core/qa-assets/commit/0710bfd617ed8cbb337b7be79efba771632e9b1f
Done! Please re-review :)
16 | + FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); 17 | + 18 | + const int64_t random_time = fuzzed_data_provider.ConsumeIntegral<int64_t>(); 19 | + const std::string random_string = fuzzed_data_provider.ConsumeRemainingBytesAsString(); 20 | + 21 | + const std::string iso8601_datetime = FormatISO8601DateTime(random_time);
This will fail when the year overflows after adding 1900. E.g.
$ base64 crash-59af3ac3c0a4395f770dbbd0f956cd680aa65a3d
AAAAALQ3CVA=
@MarcoFalke I've seen that case. I'm running with this patch in my local tree:
diff --git a/src/util/time.cpp b/src/util/time.cpp
index 2afff2626..c311c6a49 100644
--- a/src/util/time.cpp
+++ b/src/util/time.cpp
@@ -98,6 +98,14 @@ std::string FormatISO8601DateTime(int64_t nTime) {
#else
gmtime_r(&time_val, &ts);
#endif
+ if (!((ts.tm_year >= 0 && ts.tm_year <= 9999-1900) &&
+ (ts.tm_mon >= 0 && ts.tm_mon <= 11) &&
+ (ts.tm_mday >= 1 && ts.tm_mday <= 31) &&
+ (ts.tm_hour >= 0 && ts.tm_hour <= 24) &&
+ (ts.tm_min >= 0 && ts.tm_min <= 59) &&
+ (ts.tm_sec >= 0 && ts.tm_sec <= 59))) {
+ return {};
+ }
return strprintf("%04i-%02i-%02iT%02i:%02i:%02iZ", ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday, ts.tm_hour, ts.tm_min, ts.tm_sec);
}
@@ -109,6 +117,11 @@ std::string FormatISO8601Date(int64_t nTime) {
#else
gmtime_r(&time_val, &ts);
#endif
+ if (!((ts.tm_year >= 0 && ts.tm_year <= 9999-1900) &&
+ (ts.tm_mon >= 0 && ts.tm_mon <= 11) &&
+ (ts.tm_mday >= 1 && ts.tm_mday <= 31))) {
+ return {};
+ }
return strprintf("%04i-%02i-%02i", ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday);
}
Perhaps worth submitting upstreams?