diff --git a/.gitignore b/.gitignore index 226e417..25f85cc 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,6 @@ coverage.xml .mypy_cache /subprojects/gtk-blueprint-tool /blueprint-regression-tests + +/corpus +/crashes \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4356fd0..9df1287 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -25,6 +25,20 @@ build: reports: cobertura: coverage.xml +fuzz: + image: registry.gitlab.gnome.org/jwestman/blueprint-compiler + stage: build + allow_failure: true + script: + - meson _build + - ninja -C _build install + - ./tests/fuzz.sh 5000 + artifacts: + when: always + paths: + - corpus + - crashes + pages: stage: pages dependencies: diff --git a/build-aux/Dockerfile b/build-aux/Dockerfile index c7c9786..f2f168e 100644 --- a/build-aux/Dockerfile +++ b/build-aux/Dockerfile @@ -1,5 +1,9 @@ FROM fedora:latest -RUN dnf install -y meson python3-pip gtk4-devel gobject-introspection-devel libadwaita-devel +RUN dnf install -y meson python3-pip gtk4-devel gobject-introspection-devel libadwaita-devel python3-devel RUN pip3 install furo mypy sphinx coverage + +# The version on PyPI is very old and doesn't install. Use the upstream package registry instead. +RUN pip install pythonfuzz --extra-index-url https://gitlab.com/api/v4/projects/19904939/packages/pypi/simple + RUN dnf install -y git diff --git a/tests/fuzz.py b/tests/fuzz.py new file mode 100644 index 0000000..c68d7d7 --- /dev/null +++ b/tests/fuzz.py @@ -0,0 +1,27 @@ +from pythonfuzz.main import PythonFuzz + +from blueprintcompiler import tokenizer, parser, decompiler +from blueprintcompiler.completions import complete +from blueprintcompiler.errors import PrintableError, MultipleErrors, CompileError, CompilerBugError +from blueprintcompiler.tokenizer import Token, TokenType, tokenize +from blueprintcompiler import utils + +@PythonFuzz +def fuzz(buf): + try: + blueprint = buf.decode("ascii") + + tokens = tokenizer.tokenize(blueprint) + ast, errors, warnings = parser.parse(tokens) + + if errors is None and len(ast.errors) == 0: + actual = ast.generate() + except CompilerBugError as e: + raise e + except PrintableError: + pass + except UnicodeDecodeError: + pass + +if __name__ == "__main__": + fuzz() diff --git a/tests/fuzz.sh b/tests/fuzz.sh new file mode 100755 index 0000000..eedccbc --- /dev/null +++ b/tests/fuzz.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +if [ $# = 1 ]; then + RUNS="$1" +else + RUNS=-1 +fi + +mkdir -p corpus +cp tests/samples/*.blp corpus +cp tests/sample_errors/*.blp corpus +python3 tests/fuzz.py --runs $RUNS corpus \ No newline at end of file