#include "callbacks.h" #include "minify.h" #include "parser3.h" #include std::pair runStreaming(std::string copy) { MinifyState state; auto c = minifyCallbacks(); parser3::Parser3 parser(&c, &state); for (int i = 0; i < copy.size(); ++i) { auto s = parser.parse(copy.data() + i, 1); if (s != parser3::S_AGAIN) { return {state.result, s}; } } auto s = parser.parse(nullptr, 0); if (s != parser3::S_OK) { return {state.result, s}; } return {state.result, parser3::S_OK}; } std::pair runBatch(std::string copy) { MinifyState state; auto c = minifyCallbacks(); parser3::Parser3 parser(&c, &state); auto s = parser.parse(copy.data(), copy.size()); if (s != parser3::S_AGAIN) { return {state.result, s}; } s = parser.parse(nullptr, 0); if (s != parser3::S_OK) { return {state.result, s}; } return {state.result, parser3::S_OK}; } void testStreaming(std::string const &json) { auto streaming = runStreaming(json); auto batch = runBatch(json); if (streaming != batch) { if (streaming.second == batch.second && streaming.second != parser3::S_OK) { // It's ok if the processed data doesn't match if parsing failed return; } printf("streaming: %s, %s\n", streaming.second == parser3::S_OK ? "accept" : "reject", streaming.first.c_str()); printf("batch: %s, %s\n", streaming.second == parser3::S_OK ? "accept" : "reject", batch.first.c_str()); abort(); } } void compareWithSimdjson(std::string const &json) { parser3::Status ours; { auto copy = json; auto c = noopCallbacks(); parser3::Parser3 parser3(&c, nullptr); ours = parser3.parse(copy.data(), copy.size()); if (ours == parser3::S_AGAIN) { ours = parser3.parse(nullptr, 0); } } using namespace simdjson; simdjson::padded_string my_padded_data(json.data(), json.size()); simdjson::dom::parser parser; auto doc = parser.parse(my_padded_data); auto theirs = doc.error(); if (ours == parser3::S_OVERFLOW || theirs == simdjson::DEPTH_ERROR) { return; } if ((ours == parser3::S_OK) != (theirs == simdjson::SUCCESS)) { if (json.starts_with("\xef\xbb\xbf")) { // What to do with byte order mark? return; } if (theirs == simdjson::NUMBER_ERROR || theirs == simdjson::BIGINT_ERROR) { // This gets returned for precision errors sometimes? return; } if (theirs == simdjson::NUMBER_OUT_OF_RANGE) { // We don't validate the precision of numbers return; } printf("ours: %d\n", ours); printf("theirs: %d\n", theirs); abort(); } } extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { auto s = std::string((const char *)data, size); testStreaming(s); compareWithSimdjson(s); return 0; }