Files
weaseljson/src/fuzz.cpp
2025-05-19 15:11:30 -04:00

102 lines
2.8 KiB
C++

#include "callbacks.h"
#include "minify.h"
#include "parser3.h"
#include <simdjson.h>
std::pair<std::string, parser3::Status> 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<std::string, parser3::Status> 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;
}