1
0
mirror of https://github.com/stedolan/jq.git synced 2024-05-11 05:55:39 +00:00

Extend fuzzing set up

Adds a parse function ins `jv_parse.c` that enables parsing using custom
flags for the parser. This is then used by two fuzzers added as well.

This is to make sure fuzzing hits various code parts currently not
fuzzed, e.g. `stream_token`:
https://storage.googleapis.com/oss-fuzz-coverage/jq/reports/20231125/linux/src/jq/src/jv_parse.c.html#L241

Signed-off-by: David Korczynski <david@adalogics.com>
This commit is contained in:
David Korczynski
2023-11-27 16:19:56 +00:00
committed by Emanuele Torre
parent 88f01a741c
commit 44300e4310
4 changed files with 94 additions and 0 deletions

View File

@ -234,6 +234,7 @@ enum {
jv jv_parse(const char* string);
jv jv_parse_sized(const char* string, int length);
jv jv_parse_custom_flags(const char* string, int flags);
typedef void (*jv_nomem_handler_f)(void *);
void jv_nomem_handler(jv_nomem_handler_f, void *);

View File

@ -901,3 +901,46 @@ jv jv_parse_sized(const char* string, int length) {
jv jv_parse(const char* string) {
return jv_parse_sized(string, strlen(string));
}
jv jv_parse_sized_custom_flags(const char* string, int length, int flags) {
struct jv_parser parser;
parser_init(&parser, flags);
jv_parser_set_buf(&parser, string, length, 0);
jv value = jv_parser_next(&parser);
if (jv_is_valid(value)) {
jv next = jv_parser_next(&parser);
if (jv_is_valid(next)) {
// multiple JSON values, we only wanted one
jv_free(value);
jv_free(next);
value = jv_invalid_with_msg(jv_string("Unexpected extra JSON values"));
} else if (jv_invalid_has_msg(jv_copy(next))) {
// parser error after the first JSON value
jv_free(value);
value = next;
} else {
// a single valid JSON value
jv_free(next);
}
} else if (jv_invalid_has_msg(jv_copy(value))) {
// parse error, we'll return it
} else {
// no value at all
jv_free(value);
value = jv_invalid_with_msg(jv_string("Expected JSON value"));
}
parser_free(&parser);
if (!jv_is_valid(value) && jv_invalid_has_msg(jv_copy(value))) {
jv msg = jv_invalid_get_msg(value);
value = jv_invalid_with_msg(jv_string_fmt("%s (while parsing '%s')",
jv_string_value(msg),
string));
jv_free(msg);
}
return value;
}
jv jv_parse_custom_flags(const char* string, int flags) {
return jv_parse_sized_custom_flags(string, strlen(string), flags);
}

View File

@ -0,0 +1,29 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "jv.h"
int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) {
if (size < 4) {
return 0;
}
int fuzz_flags = *(int*)data;
data += 4;
size -= 4;
// Creat null-terminated string
char *null_terminated = (char *)malloc(size + 1);
memcpy(null_terminated, (char *)data, size);
null_terminated[size] = '\0';
// Fuzzer entrypoint
jv res = jv_parse_custom_flags(null_terminated, fuzz_flags);
jv_free(res);
// Free the null-terminated string
free(null_terminated);
return 0;
}

View File

@ -0,0 +1,21 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "jv.h"
int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) {
// Creat null-terminated string
char *null_terminated = (char *)malloc(size + 1);
memcpy(null_terminated, (char *)data, size);
null_terminated[size] = '\0';
// Fuzzer entrypoint
jv res = jv_parse_custom_flags(null_terminated, JV_PARSE_STREAMING);
jv_free(res);
// Free the null-terminated string
free(null_terminated);
return 0;
}