summaryrefslogtreecommitdiff
path: root/json
diff options
context:
space:
mode:
authorKaty Moe <katy@katy.moe>2021-12-15 12:00:45 +0000
committerKaty Moe <katy@katy.moe>2022-04-01 12:32:19 +0100
commit4fd729cc0730f1ceef451b7485bf5db3274bf1d6 (patch)
treed57dff23cfb047ce58ad30574f68a14b9a51f27d /json
parent8c86d68fd91a93c353e1fd5c8622f527523307db (diff)
use Go 1.18 native fuzzing
Diffstat (limited to 'json')
-rw-r--r--json/fuzz/README.md83
-rw-r--r--json/fuzz/config/corpus/attr-expr.hcl.json3
-rw-r--r--json/fuzz/config/corpus/attr-literal.hcl.json3
-rw-r--r--json/fuzz/config/corpus/block-attrs.hcl.json5
-rw-r--r--json/fuzz/config/corpus/block-empty.json3
-rw-r--r--json/fuzz/config/corpus/block-nested.hcl.json7
-rw-r--r--json/fuzz/config/corpus/empty.hcl.json1
-rw-r--r--json/fuzz/config/corpus/list-empty.json3
-rw-r--r--json/fuzz/config/corpus/list-nested.json3
-rw-r--r--json/fuzz/config/corpus/list-values.json7
-rw-r--r--json/fuzz/config/corpus/number-big.hcl.json3
-rw-r--r--json/fuzz/config/corpus/number-int.hcl.json3
-rw-r--r--json/fuzz/config/corpus/utf8.hcl.json3
-rw-r--r--json/fuzz/config/fuzz.go15
-rw-r--r--json/fuzz/fuzz_test.go20
-rw-r--r--json/fuzz/testdata/fuzz/FuzzParse/attr-expr.hcl.json2
-rw-r--r--json/fuzz/testdata/fuzz/FuzzParse/attr-literal.hcl.json2
-rw-r--r--json/fuzz/testdata/fuzz/FuzzParse/block-attrs.hcl.json2
-rw-r--r--json/fuzz/testdata/fuzz/FuzzParse/block-empty.json2
-rw-r--r--json/fuzz/testdata/fuzz/FuzzParse/block-nested.hcl.json2
-rw-r--r--json/fuzz/testdata/fuzz/FuzzParse/empty.hcl.json2
-rw-r--r--json/fuzz/testdata/fuzz/FuzzParse/list-empty.json2
-rw-r--r--json/fuzz/testdata/fuzz/FuzzParse/list-nested.json2
-rw-r--r--json/fuzz/testdata/fuzz/FuzzParse/list-values.json2
-rw-r--r--json/fuzz/testdata/fuzz/FuzzParse/number-big.hcl.json2
-rw-r--r--json/fuzz/testdata/fuzz/FuzzParse/number-int.hcl.json2
-rw-r--r--json/fuzz/testdata/fuzz/FuzzParse/utf8.hcl.json2
27 files changed, 74 insertions, 112 deletions
diff --git a/json/fuzz/README.md b/json/fuzz/README.md
index b4d7fd1..7fd0107 100644
--- a/json/fuzz/README.md
+++ b/json/fuzz/README.md
@@ -1,82 +1,59 @@
# JSON syntax fuzzing utilities
-This directory contains helper functions and corpuses that can be used to
-fuzz-test the HCL JSON parser using [go-fuzz](https://github.com/dvyukov/go-fuzz).
+This directory contains helper functions and corpora that can be used to
+fuzz-test the HCL JSON parser using Go's native fuzz testing capabilities.
-## Work directory
+Please see https://go.dev/doc/fuzz/ for more information on fuzzing.
-`go-fuzz` needs a working directory where it can keep state as it works. This
-should ideally be in a ramdisk for efficiency, and should probably _not_ be on
-an SSD to avoid thrashing it. Here's how to create a ramdisk:
+## Prerequisites
+* Go 1.18
-### macOS
-
-```
-$ SIZE_IN_MB=1024
-$ DEVICE=`hdiutil attach -nobrowse -nomount ram://$(($SIZE_IN_MB*2048))`
-$ diskutil erasevolume HFS+ RamDisk $DEVICE
-$ export RAMDISK=/Volumes/RamDisk
-```
+## Running the fuzzer
-### Linux
+Each exported function in the `json` package has a corresponding fuzz test.
+These can be run one at a time via `go test`:
```
-$ mkdir /mnt/ramdisk
-$ mount -t tmpfs -o size=1024M tmpfs /mnt/ramdisk
-$ export RAMDISK=/mnt/ramdisk
+$ cd fuzz
+$ go test -fuzz FuzzParse
```
-## Running the fuzzer
+This command will exit only when a crasher is found (see "Understanding the
+result" below).
+
+## Seed corpus
-Next, install `go-fuzz` and its build tool in your `GOPATH`:
+The seed corpus for each fuzz test function is stored in the corresponding
+directory under `json/fuzz/testdata/fuzz`. For example:
```
-$ make tools FUZZ_WORK_DIR=$RAMDISK
+$ ls json/fuzz/testdata/fuzz/FuzzParse
+attr-expr.hcl.json
+attr-literal.hcl.json
+block-attrs.hcl.json
+...
```
-Now you can fuzz the parser:
+Additional seed inputs can be added to this corpus. Each file must be in the Go 1.18 corpus file format. Files can be converted to this format using the `file2fuzz` tool. To install it:
```
-$ make fuzz-config FUZZ_WORK_DIR=$RAMDISK/json-fuzz-config
+$ go install golang.org/x/tools/cmd/file2fuzz@latest
+$ file2fuzz -help
```
-~> Note: `go-fuzz` does not interact well with `goenv`. If you encounter build
-errors where the package `go.fuzz.main` could not be found, you may need to use
-a machine with a direct installation of Go.
-
## Understanding the result
A small number of subdirectories will be created in the work directory.
If you let `go-fuzz` run for a few minutes (the more minutes the better) it
-may detect "crashers", which are inputs that caused the parser to panic. Details
-about these are written to `$FUZZ_WORK_DIR/crashers`:
+may detect "crashers", which are inputs that caused the parser to panic.
+These are written to `json/fuzz/testdata/fuzz/<fuzz test name>/`:
```
-$ ls /tmp/hcl2-fuzz-config/crashers
-7f5e9ec80c89da14b8b0b238ec88969f658f5a2d
-7f5e9ec80c89da14b8b0b238ec88969f658f5a2d.output
-7f5e9ec80c89da14b8b0b238ec88969f658f5a2d.quoted
+$ ls json/fuzz/testdata/fuzz/FuzzParseTemplate
+582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4
```
-The base file above (with no extension) is the input that caused a crash. The
-`.output` file contains the panic stack trace, which you can use as a clue to
-figure out what caused the crash.
-
A good first step to fixing a detected crasher is to copy the failing input
-into one of the unit tests in the `hcl/json` package and see it crash there
-too. After that, it's easy to re-run the test as you try to fix it. The
-file with the `.quoted` extension contains a form of the input that is quoted
-in Go syntax for easy copy-paste into a test case, even if the input contains
-non-printable characters or other inconvenient symbols.
-
-## Rebuilding for new Upstream Code
-
-An archive file is created for `go-fuzz` to use on the first run of each
-of the above, as a `.zip` file created in this directory. If upstream code
-is changed these will need to be deleted to cause them to be rebuilt with
-the latest code:
-
-```
-$ make clean
-```
+into one of the unit tests in the `json` package and see it crash there
+too. After that, it's easy to re-run the test as you try to fix it.
diff --git a/json/fuzz/config/corpus/attr-expr.hcl.json b/json/fuzz/config/corpus/attr-expr.hcl.json
deleted file mode 100644
index fa9e852..0000000
--- a/json/fuzz/config/corpus/attr-expr.hcl.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "foo": "${upper(bar + baz[1])}"
-}
diff --git a/json/fuzz/config/corpus/attr-literal.hcl.json b/json/fuzz/config/corpus/attr-literal.hcl.json
deleted file mode 100644
index e63d37b..0000000
--- a/json/fuzz/config/corpus/attr-literal.hcl.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "foo": "bar"
-}
diff --git a/json/fuzz/config/corpus/block-attrs.hcl.json b/json/fuzz/config/corpus/block-attrs.hcl.json
deleted file mode 100644
index 4130811..0000000
--- a/json/fuzz/config/corpus/block-attrs.hcl.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "block": {
- "foo": true
- }
-}
diff --git a/json/fuzz/config/corpus/block-empty.json b/json/fuzz/config/corpus/block-empty.json
deleted file mode 100644
index 6974555..0000000
--- a/json/fuzz/config/corpus/block-empty.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "block": {}
-}
diff --git a/json/fuzz/config/corpus/block-nested.hcl.json b/json/fuzz/config/corpus/block-nested.hcl.json
deleted file mode 100644
index 9d964e0..0000000
--- a/json/fuzz/config/corpus/block-nested.hcl.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "block": {
- "another_block": {
- "foo": "bar"
- }
- }
-}
diff --git a/json/fuzz/config/corpus/empty.hcl.json b/json/fuzz/config/corpus/empty.hcl.json
deleted file mode 100644
index 0967ef4..0000000
--- a/json/fuzz/config/corpus/empty.hcl.json
+++ /dev/null
@@ -1 +0,0 @@
-{}
diff --git a/json/fuzz/config/corpus/list-empty.json b/json/fuzz/config/corpus/list-empty.json
deleted file mode 100644
index a8471f7..0000000
--- a/json/fuzz/config/corpus/list-empty.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "hello": []
-}
diff --git a/json/fuzz/config/corpus/list-nested.json b/json/fuzz/config/corpus/list-nested.json
deleted file mode 100644
index 27bdf4f..0000000
--- a/json/fuzz/config/corpus/list-nested.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "hello": [[]]
-}
diff --git a/json/fuzz/config/corpus/list-values.json b/json/fuzz/config/corpus/list-values.json
deleted file mode 100644
index 6def6cf..0000000
--- a/json/fuzz/config/corpus/list-values.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "hello": [
- "hello",
- true,
- 1.2
- ]
-}
diff --git a/json/fuzz/config/corpus/number-big.hcl.json b/json/fuzz/config/corpus/number-big.hcl.json
deleted file mode 100644
index 8360c69..0000000
--- a/json/fuzz/config/corpus/number-big.hcl.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "foo": 1.234234e30
-}
diff --git a/json/fuzz/config/corpus/number-int.hcl.json b/json/fuzz/config/corpus/number-int.hcl.json
deleted file mode 100644
index bab9613..0000000
--- a/json/fuzz/config/corpus/number-int.hcl.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "foo": 1024
-}
diff --git a/json/fuzz/config/corpus/utf8.hcl.json b/json/fuzz/config/corpus/utf8.hcl.json
deleted file mode 100644
index 55afd36..0000000
--- a/json/fuzz/config/corpus/utf8.hcl.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "foo": "föo ${föo(\"föo\")}"
-}
diff --git a/json/fuzz/config/fuzz.go b/json/fuzz/config/fuzz.go
deleted file mode 100644
index aa6214e..0000000
--- a/json/fuzz/config/fuzz.go
+++ /dev/null
@@ -1,15 +0,0 @@
-package fuzzconfig
-
-import (
- "github.com/hashicorp/hcl/v2/json"
-)
-
-func Fuzz(data []byte) int {
- _, diags := json.Parse(data, "<fuzz-conf>")
-
- if diags.HasErrors() {
- return 0
- }
-
- return 1
-}
diff --git a/json/fuzz/fuzz_test.go b/json/fuzz/fuzz_test.go
new file mode 100644
index 0000000..bcaa4f4
--- /dev/null
+++ b/json/fuzz/fuzz_test.go
@@ -0,0 +1,20 @@
+package fuzzjson
+
+import (
+ "testing"
+
+ "github.com/hashicorp/hcl/v2/json"
+)
+
+func FuzzParse(f *testing.F) {
+f.Fuzz(func(t *testing.T, data []byte) {
+ _, diags := json.Parse(data, "<fuzz-conf>")
+
+if diags.HasErrors() {
+ t.Logf("Error when parsing JSON %v", data)
+ for _, diag := range diags {
+ t.Logf("- %s", diag.Error())
+ }
+ }
+})
+}
diff --git a/json/fuzz/testdata/fuzz/FuzzParse/attr-expr.hcl.json b/json/fuzz/testdata/fuzz/FuzzParse/attr-expr.hcl.json
new file mode 100644
index 0000000..8620bcd
--- /dev/null
+++ b/json/fuzz/testdata/fuzz/FuzzParse/attr-expr.hcl.json
@@ -0,0 +1,2 @@
+go test fuzz v1
+[]byte("{\n \"foo\": \"${upper(bar + baz[1])}\"\n}\n") \ No newline at end of file
diff --git a/json/fuzz/testdata/fuzz/FuzzParse/attr-literal.hcl.json b/json/fuzz/testdata/fuzz/FuzzParse/attr-literal.hcl.json
new file mode 100644
index 0000000..32e599d
--- /dev/null
+++ b/json/fuzz/testdata/fuzz/FuzzParse/attr-literal.hcl.json
@@ -0,0 +1,2 @@
+go test fuzz v1
+[]byte("{\n \"foo\": \"bar\"\n}\n") \ No newline at end of file
diff --git a/json/fuzz/testdata/fuzz/FuzzParse/block-attrs.hcl.json b/json/fuzz/testdata/fuzz/FuzzParse/block-attrs.hcl.json
new file mode 100644
index 0000000..45ec09f
--- /dev/null
+++ b/json/fuzz/testdata/fuzz/FuzzParse/block-attrs.hcl.json
@@ -0,0 +1,2 @@
+go test fuzz v1
+[]byte("{\n \"block\": {\n \"foo\": true\n }\n}\n") \ No newline at end of file
diff --git a/json/fuzz/testdata/fuzz/FuzzParse/block-empty.json b/json/fuzz/testdata/fuzz/FuzzParse/block-empty.json
new file mode 100644
index 0000000..88d7816
--- /dev/null
+++ b/json/fuzz/testdata/fuzz/FuzzParse/block-empty.json
@@ -0,0 +1,2 @@
+go test fuzz v1
+[]byte("{\n \"block\": {}\n}\n") \ No newline at end of file
diff --git a/json/fuzz/testdata/fuzz/FuzzParse/block-nested.hcl.json b/json/fuzz/testdata/fuzz/FuzzParse/block-nested.hcl.json
new file mode 100644
index 0000000..276096a
--- /dev/null
+++ b/json/fuzz/testdata/fuzz/FuzzParse/block-nested.hcl.json
@@ -0,0 +1,2 @@
+go test fuzz v1
+[]byte("{\n \"block\": {\n \"another_block\": {\n \"foo\": \"bar\"\n }\n }\n}\n") \ No newline at end of file
diff --git a/json/fuzz/testdata/fuzz/FuzzParse/empty.hcl.json b/json/fuzz/testdata/fuzz/FuzzParse/empty.hcl.json
new file mode 100644
index 0000000..fbe4fab
--- /dev/null
+++ b/json/fuzz/testdata/fuzz/FuzzParse/empty.hcl.json
@@ -0,0 +1,2 @@
+go test fuzz v1
+[]byte("{}\n") \ No newline at end of file
diff --git a/json/fuzz/testdata/fuzz/FuzzParse/list-empty.json b/json/fuzz/testdata/fuzz/FuzzParse/list-empty.json
new file mode 100644
index 0000000..ad1b075
--- /dev/null
+++ b/json/fuzz/testdata/fuzz/FuzzParse/list-empty.json
@@ -0,0 +1,2 @@
+go test fuzz v1
+[]byte("{\n \"hello\": []\n}\n") \ No newline at end of file
diff --git a/json/fuzz/testdata/fuzz/FuzzParse/list-nested.json b/json/fuzz/testdata/fuzz/FuzzParse/list-nested.json
new file mode 100644
index 0000000..fb2e779
--- /dev/null
+++ b/json/fuzz/testdata/fuzz/FuzzParse/list-nested.json
@@ -0,0 +1,2 @@
+go test fuzz v1
+[]byte("{\n \"hello\": [[]]\n}\n") \ No newline at end of file
diff --git a/json/fuzz/testdata/fuzz/FuzzParse/list-values.json b/json/fuzz/testdata/fuzz/FuzzParse/list-values.json
new file mode 100644
index 0000000..8b2d4e9
--- /dev/null
+++ b/json/fuzz/testdata/fuzz/FuzzParse/list-values.json
@@ -0,0 +1,2 @@
+go test fuzz v1
+[]byte("{\n \"hello\": [\n \"hello\",\n true,\n 1.2\n ]\n}\n") \ No newline at end of file
diff --git a/json/fuzz/testdata/fuzz/FuzzParse/number-big.hcl.json b/json/fuzz/testdata/fuzz/FuzzParse/number-big.hcl.json
new file mode 100644
index 0000000..7b59d7d
--- /dev/null
+++ b/json/fuzz/testdata/fuzz/FuzzParse/number-big.hcl.json
@@ -0,0 +1,2 @@
+go test fuzz v1
+[]byte("{\n \"foo\": 1.234234e30\n}\n") \ No newline at end of file
diff --git a/json/fuzz/testdata/fuzz/FuzzParse/number-int.hcl.json b/json/fuzz/testdata/fuzz/FuzzParse/number-int.hcl.json
new file mode 100644
index 0000000..0a6f064
--- /dev/null
+++ b/json/fuzz/testdata/fuzz/FuzzParse/number-int.hcl.json
@@ -0,0 +1,2 @@
+go test fuzz v1
+[]byte("{\n \"foo\": 1024\n}\n") \ No newline at end of file
diff --git a/json/fuzz/testdata/fuzz/FuzzParse/utf8.hcl.json b/json/fuzz/testdata/fuzz/FuzzParse/utf8.hcl.json
new file mode 100644
index 0000000..b20b2c6
--- /dev/null
+++ b/json/fuzz/testdata/fuzz/FuzzParse/utf8.hcl.json
@@ -0,0 +1,2 @@
+go test fuzz v1
+[]byte("{\n \"foo\": \"föo ${föo(\\\"föo\\\")}\"\n}\n") \ No newline at end of file