When I heard about stc and Ezno, both attempts to rewrite TypeScript in Rust, I was dubious. Ezno exists though! I'm excited and impressed by the work that Ben has been able to put into it, and I've attempted to provide my share of input via fuzz testing harnesses, helped in creation by my friend Addison Crump.
We started with a naive string-based fuzzer, which just spewed valid UTF-8 strings into the module parser.
The fuzzer harness is defined via a do_fuzz()
function that takes a string as input and returns whether the run was useful (Corpus:Keep
, Corpus:Reject
) as output. Since this is a very simple and naive input, and a parser written in a generally memory safe language (rust), we need a stronger oracle for bug finding.
To do so, we parse the string once, and reject if the parse fails. This allows us to weed out inputs that aren't acceptable to the parser, while implicitly testing that the parser does not panic on arbitrary strings.
Next, we use the built-in printer to take the AST the parser produced and print it back into a string. We parse the printed string again, this time panicking if the parse fails, since that would mean the parser disagrees with itself when parsing the same value twice
Finally, we can print out the second AST and compare it to the first printed AST and compare whether the parser's printed representation of the code is also self-consistent. If all of these assertions pass, we return Corpus:Keep
to indicate that it is still an interesting code-path even though it didn't cause an error.
This has been able to catch a good number of incomplete bits of the parser, where a category of syntax wasn't completed yet, and there were still todo!()
' s about. Today, the fuzzer runs in CI and doesn't find as much, but I'm still working through and helping report examples found by running the fuzzer on my M1 Max MacBook Pro.
Ben has been very receptive to these bug reports and has been able to provide fixes for them rather quickly! He fixed both issues in one PR:
In an update I'll write about the other approach we took to adding a fuzzer for the ezno parser.