summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorDavid Korczynski <david@adalogics.com>2023-12-06 22:46:45 +0000
committerEmanuele Torre <torreemanuele6@gmail.com>2023-12-07 12:57:54 +0100
commit5029328d35f3e60037970d27f350a742af41aa02 (patch)
treed65a94a4533d55cecde9574a5da442a503b0954a /tests
parent20a403e97eb0d951b00934939469f6d8f4163601 (diff)
tests: add new fuzzer
Signed-off-by: David Korczynski <david@adalogics.com>
Diffstat (limited to 'tests')
-rw-r--r--tests/jq_fuzz_fixed.cpp297
1 files changed, 297 insertions, 0 deletions
diff --git a/tests/jq_fuzz_fixed.cpp b/tests/jq_fuzz_fixed.cpp
new file mode 100644
index 00000000..3dd955bb
--- /dev/null
+++ b/tests/jq_fuzz_fixed.cpp
@@ -0,0 +1,297 @@
+#include <fuzzer/FuzzedDataProvider.h>
+#include <string>
+
+#include "jq.h"
+#include "jv.h"
+
+
+const char *jq_progs[] = {
+ ". / \", \"",
+ ".[]",
+ "$ENV.PAGER",
+ ".[0]",
+ ". < 0.12345678901234567890123456788",
+ ".[] == 1",
+ ".[] | (1 / .)?",
+ "10 / . * 3",
+ "[1,2,empty,3]",
+ "1, empty, 2",
+ "[.,1]|until(.[0] < 1; [.[0] - 1, .[1] * .[0]])|.[1]",
+ ".[-2:]",
+ ".[-2]",
+ ".[2]",
+ "[ .[] | . * 2]",
+ ".[2:4]",
+ "(. + 2) * 5",
+ ".[:3]",
+ ".[4,2]",
+ "42 and \"a string\"",
+ "4 - .a",
+ ". < 5",
+ ".. | .a?",
+ "[.[] | .a?]",
+ ".a + 1",
+ "{a: 1} + {b: 2} + {c: 3} + {a: 42}",
+ ".a + .b",
+ ".a = .b",
+ ".a |= .b",
+ "add",
+ "all",
+ ".a + null",
+ "any",
+ ".[] as [$a, $b] | {a: $a, b: $b}",
+ ". as [$a, $b, {c: $c}] | $a + $b + $c",
+ ".[] as {$a, $b, c: {$d}} ?// {$a, $b, c: [{$e}]} | {$a, $b, $d, $e}",
+ ".[] as {$a, $b, c: {$d, $e}} ?// {$a, $b, c: [{$d, $e}]} | {$a, $b, "
+ "$d, $e}",
+ ".[] as [$a] ?// [$b] | if $a != null then error(\"err: \($a)\") else "
+ "{$a,$b} end",
+ ". as $big | [$big, $big + 1] | map(. > "
+ "10000000000000000000000000000000)",
+ ". as $dot|fromstream($dot|tostream)|.==$dot",
+ ". as $i|[(.*2|. as $i| $i), $i]",
+ "ascii_upcase",
+ ".bar as $x | .foo | . + $x",
+ "@base64",
+ "@base64d",
+ ". == {\"b\": {\"d\": (4 + 1e-20), \"c\": 3}, \"a\":1}",
+ "bsearch(0)",
+ "bsearch(4) as $ix | if $ix < 0 then .[-(1+$ix)] = 4 else . end",
+ "capture(\"(?<a>[a-z]+)-(?<n>[0-9]+)\")",
+ "capture(\"(?<a>[a-z]+)-(?<n>[0-9]+)\")",
+ "combinations",
+ "combinations(2)",
+ "contains(\"bar\")",
+ "contains([\"baz\", \"bar\"])",
+ "contains([\"bazzzzz\", \"bar\"])",
+ "contains({foo: 12, bar: [{barp: 15}]})",
+ "def addvalue(f): f as $x | map(. + $x); addvalue(.[0])",
+ "def addvalue(f): . + [f]; map(addvalue(.[0]))",
+ "def while(cond; update): def _while: if cond then ., (update | "
+ "_while) else empty end; _while; [while(.<100; .*2)]",
+ "del(.[1, 2])",
+ "del(.foo)",
+ "delpaths([[\"a\",\"b\"]])",
+ "empty // 42",
+ "[.[]|endswith(\"foo\")]",
+ "env.PAGER",
+ "explode",
+ ". == false",
+ "(false, null, 1) // 42",
+ "(false, null, 1) | . // 42",
+ "flatten",
+ "flatten(1)",
+ "floor",
+ ".[\"foo\"]",
+ ".[\"foo\"]?",
+ ".foo",
+ ".foo?",
+ ".foo[]",
+ "[.foo?]",
+ ".foo += 1",
+ ".foo // 42",
+ ".foo, .bar",
+ "foreach .[] as $item (0; . + $item)",
+ "foreach .[] as $item (0; . + $item; [$item, . * 2])",
+ "foreach .[] as $item (0; . + 1; {index: ., $item})",
+ "fromdate",
+ "from_entries",
+ "fromstream(1|truncate_stream([[0],1],[[1,0],2],[[1,0]],[[1]]))",
+ "getpath([\"a\",\"b\"])",
+ "[getpath([\"a\",\"b\"], [\"a\",\"c\"])]",
+ "group_by(.foo)",
+ "[.[] | gsub(\", \"; \":\")]",
+ "gsub(\"$\"; \"a\"; \"g\")",
+ "gsub(\"^\"; \"a\")",
+ "[gsub(\"(?<a>.)\"; \"\(.a|ascii_upcase)\", \"\(.a|ascii_downcase)\", "
+ "\"c\")]",
+ "gsub(\"^.*?a\"; \"b\")",
+ "gsub(\"^.*a\"; \"b\")",
+ "gsub(\"a\";\"b\")",
+ "gsub(\"\"; \"a\"; \"g\")",
+ "gsub(\"\"; \"a\"; \"g\")",
+ "gsub(\"[^a-z]*(?<x>[a-z]*)\"; \"Z\(.x)\")",
+ "gsub(\"\\b(?<x>.)\"; \"\(.x|ascii_downcase)\")",
+ "gsub(\"(?<d>\\d)\"; \":\(.d);\")",
+ "gsub(\"^\"; \"\"; \"g\")",
+ "[gsub(\"p\"; \"a\", \"b\")]",
+ "gsub(\"(?=u)\"; \"u\")",
+ "gsub(\"(.*)\"; \"\"; \"x\")",
+ "gsub(\"(?<x>.)[^a]*\"; \"+\(.x)-\")",
+ "gsub(\"(?<x>.)(?<y>[0-9])\"; \"\(.x|ascii_downcase)\(.y)\")",
+ "@html",
+ "if . == 0 then \"zero\" elif . == 1 then \"one\" else \"many\" "
+ "end",
+ "implode",
+ "index(\", \")",
+ "index(1)",
+ "index([1,2])",
+ "indices(\", \")",
+ "indices(1)",
+ "indices([1,2])",
+ ".[] | (infinite * .) < 0",
+ "infinite, nan | type",
+ ".[] | in({\"foo\": 42})",
+ "inside({\"foo\": 12, \"bar\":[1,2,{\"barp\":12, \"blip\":13}]})",
+ "inside({\"foo\": 12, \"bar\":[1,2,{\"barp\":12, \"blip\":13}]})",
+ "inside(\"foobar\")",
+ "inside([\"foobar\", \"foobaz\", \"blarp\"])",
+ "inside([\"foobar\", \"foobaz\", \"blarp\"])",
+ "isempty(.[])",
+ "isempty(.[])",
+ "isempty(empty)",
+ "join(\" \")",
+ "join(\", \")",
+ "keys",
+ "keys",
+ ".[] | length",
+ "[limit(3;.[])]",
+ "[.[]|ltrimstr(\"foo\")]",
+ "map(., .)",
+ "map(.+1)",
+ "map([., . == 1]) | tojson",
+ "map(abs)",
+ "map(has(2))",
+ "map(has(\"foo\"))",
+ "map(in([0,1]))",
+ "map(select(. >= 2))",
+ "map(type)",
+ "map_values(.+1)",
+ "map_values(. // empty)",
+ "match(\"(abc)+\"; \"g\")",
+ "[match(\"a\"; \"gi\")]",
+ "[match(\".+?\\b\")]",
+ "[match([\"(bar)\"])]",
+ "match(\"foo\")",
+ "[match([\"foo (?<bar123>bar)? foo\", \"ig\"])]",
+ "match(\"foo (?<bar123>bar)? foo\"; \"ig\")",
+ "match([\"foo\", \"ig\"])",
+ "[match(\"\"; \"g\")]",
+ "[ match(\".\"; \"g\")] | length",
+ "[match(\"( )*\"; \"gn\")]",
+ "max_by(.foo)",
+ "min",
+ ".[] | .name",
+ ".[]|numbers",
+ "[path(..)]",
+ "path(.a[0].b)",
+ "[paths]",
+ "[paths(type == \"number\")]",
+ "pick(.[2], .[0], .[0])",
+ "pick(.a, .b.c, .x)",
+ "[range(0; 10; -1)]",
+ "[range(0; 10; 3)]",
+ "[range(0; -5; -1)]",
+ "[range(2; 4)]",
+ "range(2; 4)",
+ "[range(4)]",
+ "[range(.)]|[first, last, nth(5)]",
+ "recurse",
+ "recurse(. * .; . < 20)",
+ "recurse(.foo[])",
+ "reduce .[] as [$i,$j] (0; . + $i * $j)",
+ "reduce .[] as $item (0; . + $item)",
+ "reduce .[] as {$x,$y} (null; .x += $x | .y += [$y])",
+ "[repeat(.*2, error)?]",
+ "reverse",
+ "rindex(\", \")",
+ "rindex(1)",
+ "rindex([1,2])",
+ "[.[]|rtrimstr(\"foo\")]",
+ "[.[] | scan(\", \")]",
+ "[.[] | scan(\"b+\"; \"i\")]",
+ "scan(\"c\")",
+ ".[] | select(.id == \"second\")",
+ "(..|select(type==\"boolean\")) |= if . then 1 else 0 end",
+ "setpath([0,\"a\"]; 1)",
+ "setpath([\"a\",\"b\"]; 1)",
+ "setpath([\"a\",\"b\"]; 1)",
+ "@sh \"echo \(.)\"",
+ "sort",
+ "sort_by(.foo)",
+ "sort_by(.foo, .bar)",
+ "split(\", *\"; null)",
+ "splits(\", *\")",
+ "sqrt",
+ "[.[]|startswith(\"foo\")]",
+ "strptime(\"%Y-%m-%dT%H:%M:%SZ\")",
+ "strptime(\"%Y-%m-%dT%H:%M:%SZ\")|mktime",
+ "[sub(\"(?<a>.)\"; \"\(.a|ascii_upcase)\", \"\(.a|ascii_downcase)\")]",
+ "[sub(\"(?<a>.)\"; \"\(.a|ascii_upcase)\", \"\(.a|ascii_downcase)\", "
+ "\"c\")]",
+ "[sub(\"a\"; \"b\", \"c\")]",
+ "sub(\"[^a-z]*(?<x>[a-z]+)\"; \"Z\(.x)\"; \"g\")",
+ "[.[]|[[sub(\", *\";\":\")], [gsub(\", *\";\":\")], [scan(\", *\")]]]",
+ "[.[]|[[sub(\", +\";\":\")], [gsub(\", +\";\":\")], [scan(\", +\")]]]",
+ "sub(\"^(?<head>.)\"; \"Head=\(.head) Tail=\")",
+ "[test(\"ā\")]",
+ ".[] | test(\"a b c # spaces are ignored\"; \"ix\")",
+ "test(\"foo\")",
+ "to_entries",
+ "[., tojson]",
+ "[.[]|tojson]",
+ "[.[]|tojson|fromjson]",
+ ".[] | tonumber",
+ "[.[] | tonumber?]",
+ ".[] | tostring",
+ "[.[]|tostring]",
+ "transpose",
+ "[true, false | not]",
+ "(true, false) or false",
+ "(true, true) and (true, false)",
+ "truncate_stream([[0],1],[[1,0],2],[[1,0]],[[1]])",
+ "[.[]|try .a]",
+ "unique",
+ "unique_by(.foo)",
+ "unique_by(length)",
+ ".user, .projects[]",
+ "[.user, .projects[]]",
+ "{(.user): .titles}",
+ "{user, title: .titles[]}",
+ "utf8bytelength",
+ "walk(if type == \"array\" then sort else . end)",
+ "walk( if type == \"object\" then with_entries( .key |= sub( \"^_+\"; "
+ "\"\") ) else . end )",
+ "[while(.<100; .*2)]",
+ "with_entries(.key |= \"KEY_\" + .)",
+ ". - [\"xml\", \"yaml\"]",
+};
+
+// Fuzzer inspired by /src/jq_test.c
+// The goal is to have the fuzzer execute the functions:
+// jq_compile -> jv_parse -> jq_next.
+extern "C" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) {
+ FuzzedDataProvider fdp(data, size);
+ std::string parse_payload1 = fdp.ConsumeRandomLengthString();
+ std::string parse_payload2 = fdp.ConsumeRandomLengthString();
+
+ int idx = fdp.ConsumeIntegralInRange<int>(
+ 0, (sizeof(jq_progs) / sizeof(char *)) - 1);
+
+ jq_state *jq = NULL;
+ jq = jq_init();
+ if (jq != NULL) {
+ jq_set_attr(jq, jv_string("JQ_ORIGIN"), jv_string("/tmp/"));
+
+ if (jq_compile(jq, jq_progs[idx])) {
+ // Process to jv_parse and then jv_next
+ jv input = jv_parse(parse_payload1.c_str());
+ if (jv_is_valid(input)) {
+ jq_start(jq, input, 0);
+ jv next = jv_parse(parse_payload2.c_str());
+ if (jv_is_valid(next)) {
+ jv actual = jq_next(jq);
+ jv_free(actual);
+ }
+ jv_free(next);
+ } else {
+ // Only free if input is invalid as otherwise jq_teardown
+ // frees it.
+ jv_free(input);
+ }
+ }
+ }
+ jq_teardown(&jq);
+
+ return 0;
+}