Repository navigation
GH-54903: [C++][OSS-Fuzz fuzzing] Update csv fuzzer and corpora/dict preparation - #54912
arthurscchan wants to merge 1 commit into
Conversation
Signed-off-by: Arthur Chan <arthur.chan@adalogics.com>
|
Thanks for the PR @arthurscchan . Is there any reason this doesn't reuse our standard PR description template? |
pitrou
left a comment
There was a problem hiding this comment.
Thanks for doing this. On the principle this is interesting, but I think there are number of problems with the current implementation.
| # Add examples from Pandas test suite | ||
| find "${PANDAS_DIR}/" -name "*.csv" -exec cp --backup=numbered '{}' "${CORPUS_DIR}" \; | ||
| # Some Pandas CSV files are exact duplicates of each other under different | ||
| # names, and pack_corpus.py fails on duplicate hashes; keep only one copy. |
There was a problem hiding this comment.
Hmm, can pack_corpus.py be changed to not fail on duplicate hashes then? Perhaps it should just emit a warning instead of failing?
| @@ -0,0 +1,60 @@ | |||
| # Tokens for arrow-csv-fuzz: CSV dialect characters, null/bool spellings, | |||
| # numeric edge cases and timestamp formats understood by the Arrow CSV reader. | |||
There was a problem hiding this comment.
Ok, it's not clear to me how dictionaries are used by the fuzzing engine.
Are inputs restricted to a combination of tokens from the dictionaries? Or are random mutations still applied on top?
| opts.parse.delimiter = kDelimiters[header[0] % 5]; | ||
| opts.parse.quoting = !(header[1] & 1); |
There was a problem hiding this comment.
Hmm, instead of all the manual bit-twiddling here, can we use a dedicated packed structure with bit-fields?
Can get inspiration from the Parquet encoding fuzzer:
arrow/cpp/src/parquet/arrow/fuzz_encoding_internal.cc
Lines 70 to 88 in 373d64c
| ConvertOptions convert; | ||
| }; | ||
|
|
||
| FuzzCsvOptions MakeFuzzCsvOptions(const uint8_t* header) { |
There was a problem hiding this comment.
Just like in
, it would be nicer for this function to take astd::span<const uint8_t> IMHO.
| parse_options, convert_options)); | ||
| ARROW_ASSIGN_OR_RAISE( | ||
| auto table_reader, | ||
| TableReader::Make(io_context, input, read_options, opts.parse, opts.convert)); |
There was a problem hiding this comment.
At this point, the input has been exhausted by the previous table reader call, so you'd just getting an empty table here?
| return table->ValidateFull(); | ||
| }; | ||
| st &= table->ValidateFull(); | ||
| } |
There was a problem hiding this comment.
Note: if all three table reads are successful, we may want to add differential fuzzing, i.e. test that all three tables are equal (but there may be legitimate reasons why they are not?).
| // Small batch sizes exercise the writer's chunking and produce files that | ||
| // make the reader merge many batches. |
There was a problem hiding this comment.
I'm not sure we care about exercising the writer here. We're just generating files for the reader.
And since those are CSV files, there is no inherent chunking in the file contents, so I don't understand what this is achieving.
| // Legacy behavior for inputs without a full header: the original | ||
| // hardcoded options. Small block sizes make chunking more likely to be | ||
| // exercised, as most legacy corpus entries are in the 4-10 kB range. |
There was a problem hiding this comment.
Well, the header is small (8 bytes), and most legacy inputs will actually go through the other code path, and get a non-sensical header as well as an unexpected non-header payload.
There was a problem hiding this comment.
A possible workaround would be to have a magic number in front of the new header. If the magic number matches, parse the header, otherwise consider the input legacy.
| ARROW_ASSIGN_OR_RAISE(auto sample_fn, dir_fn.Join(sample_name())); | ||
| std::cerr << sample_fn.ToString() << std::endl; | ||
| ARROW_ASSIGN_OR_RAISE(auto file, io::FileOutputStream::Open(sample_fn.ToString())); | ||
| RETURN_NOT_OK(file->Write(buffer)); |
There was a problem hiding this comment.
We should also be writing the serialized FuzzCsvOptions header, no?
See the Parquet encoding fuzzer for how this can be done.
|
cc @addisoncrump if you want a bit more of fuzzing-related fun :) |
This PR updates the csv fuzzer with new corpora/dict, together with google/oss-fuzz#16332 to improve the fuzzer for project arrow. This PR is the 3rd PR aiming to improve the overall fuzzing coverage and effectiveness of the arrow project, mentioned in #54903.