diff --git a/lang/Makefile b/lang/Makefile
index 0fd1def3..7e2d49c5 100644
--- a/lang/Makefile
+++ b/lang/Makefile
@@ -16,7 +16,7 @@
# along with this program. If not, see .
SHELL = /usr/bin/env bash
-.PHONY: all build clean
+.PHONY: all build clean fuzz
OLDGOYACC := $(shell go version | grep -E 'go1.6|go1.7')
@@ -44,3 +44,6 @@ else
goyacc parser.y
endif
@ROOT="$$( cd "$$( dirname "$${BASH_SOURCE[0]}" )" && cd .. && pwd )" && $$ROOT/misc/header.sh 'y.go'
+
+fuzz:
+ @$(MAKE) --quiet -C fuzz
diff --git a/lang/fuzz/.gitignore b/lang/fuzz/.gitignore
new file mode 100644
index 00000000..9d9320bb
--- /dev/null
+++ b/lang/fuzz/.gitignore
@@ -0,0 +1,4 @@
+corpus/
+crashers/
+suppressions/
+fuzz-fuzz.zip
diff --git a/lang/fuzz/Makefile b/lang/fuzz/Makefile
new file mode 100644
index 00000000..a51cbb8d
--- /dev/null
+++ b/lang/fuzz/Makefile
@@ -0,0 +1,27 @@
+# Mgmt
+# Copyright (C) 2013-2020+ James Shubin and the project contributors
+# Written by James Shubin and the project contributors
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+SHELL = /usr/bin/env bash
+.PHONY: all fuzz
+
+all: fuzz
+
+fuzz:
+ mkdir -p corpus
+ find ../.. -name \*.mcl -exec cp {} corpus \;
+ go-fuzz-build
+ go-fuzz -bin=./lang-fuzz.zip -workdir=.
diff --git a/lang/fuzz/fuzz.go b/lang/fuzz/fuzz.go
new file mode 100644
index 00000000..d00858a2
--- /dev/null
+++ b/lang/fuzz/fuzz.go
@@ -0,0 +1,43 @@
+// Mgmt
+// Copyright (C) 2013-2020+ James Shubin and the project contributors
+// Written by James Shubin and the project contributors
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+package fuzz
+
+import (
+ "bytes"
+
+ "github.com/purpleidea/mgmt/lang"
+)
+
+// Fuzz is repeatedly called by go-fuzz with semi-random inputs in an attempt to
+// make the Lexer/Parser crash. From the go-fuzz docs: Data is a random input
+// generated by go-fuzz, note that in most cases it is invalid. The function
+// must return 1 if the fuzzer should increase priority of the given input
+// during subsequent fuzzing (for example, the input is lexically correct and
+// was parsed successfully); -1 if the input must not be added to corpus even if
+// gives new coverage; and 0 otherwise; other values are reserved for future
+// use.
+func Fuzz(data []byte) int {
+ ast, err := lang.LexParse(bytes.NewReader(data))
+ if err != nil {
+ if ast != nil {
+ panic("ast != nil on error")
+ }
+ return 0
+ }
+ return 1
+}
diff --git a/misc/make-deps.sh b/misc/make-deps.sh
index 01896618..cf557da5 100755
--- a/misc/make-deps.sh
+++ b/misc/make-deps.sh
@@ -128,6 +128,7 @@ go get golang.org/x/tools/cmd/stringer # for automatic stringer-ing
go get golang.org/x/lint/golint # for `golint`-ing
go get golang.org/x/tools/cmd/goimports # for fmt
go get github.com/tmthrgd/go-bindata/go-bindata # for compiling in non golang files
+go get golang.org/dvyukov/go-fuzz # for fuzzing the mcl lang bits
if env | grep -q -e '^TRAVIS=true$' -e '^JENKINS_URL=' -e '^BUILD_TAG=jenkins'; then
go get -u gopkg.in/alecthomas/gometalinter.v1 && mv "$(dirname $(command -v gometalinter.v1))/gometalinter.v1" "$(dirname $(command -v gometalinter.v1))/gometalinter" && gometalinter --install # bonus
fi