38 lines
1.7 KiB
C
38 lines
1.7 KiB
C
// fuzzParser.c -- one libFuzzer driver, compiled once per parser. The build selects the parser by
|
|
// #include'ing its whole translation unit (so the static entry point is visible) and naming its
|
|
// native via -DFUZZ_INCLUDE and -DFUZZ_NATIVE, e.g.
|
|
//
|
|
// clang -fsanitize=fuzzer,address,undefined -DFUZZ_INCLUDE='"calogJson.c"' \
|
|
// -DFUZZ_NATIVE=jsonParseNative ... tests/fuzzParser.c src/value.c src/broker.c ...
|
|
//
|
|
// Each parser native has the same shape (CalogValueT *args, int32_t argCount, CalogValueT *result,
|
|
// void *userData): we wrap the raw fuzz bytes in a binary-safe string as args[0] and drive the
|
|
// parser directly, so the fuzzer explores the parser/marshaller, not the script layer. See the
|
|
// `make fuzz` target. Build with clang throughout -- libcalog.a is gcc-ASan and cannot be mixed
|
|
// with clang's fuzzer/ASan runtime, so the core sources are compiled fresh alongside this file.
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
#include "calog.h"
|
|
|
|
// The parser under test, pulled in whole so its static native is reachable.
|
|
#include FUZZ_INCLUDE
|
|
|
|
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
|
CalogValueT args[1];
|
|
CalogValueT result;
|
|
|
|
if (calogValueString(&args[0], (const char *)data, (int64_t)size) != calogOkE) {
|
|
return 0;
|
|
}
|
|
// argCount 1: parsers that take an optional second argument (e.g. csvParse's delimiter) use
|
|
// their default, which is exactly the path we want to hammer with arbitrary input.
|
|
if (FUZZ_NATIVE(args, 1, &result, NULL) == calogOkE) {
|
|
calogValueFree(&result);
|
|
} else {
|
|
calogValueFree(&result); // a failed parse still initialises result (calogFail path)
|
|
}
|
|
calogValueFree(&args[0]);
|
|
return 0;
|
|
}
|