summaryrefslogtreecommitdiff
path: root/tests/test_fuzz_parser.py
blob: db55d0d50a8497ce882744ad297ef9912125e352 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0

"""Fuzz test PythonParser.parse_source

This runs on OSS-Fuzz where coveragepy's set is located at:
https://github.com/google/oss-fuzz/tree/master/projects/coveragepy

It is configured to be a unit test as well, which makes it easier to test
during development, e.g. to catch breaking changes.

The goal of the fuzzing by way of OSS-Fuzz is to:
- Find any uncaught illegitimate exceptions.
- Find any security vulnerabilities as identified by pysecsan:
  https://pypi.org/project/pysecsan/
  Notice, pysecsan will be enabled by OSS-Fuzz and is not explicitly enabled
  here.
"""

import sys
import atheris
import pytest

from coverage.exceptions import NotPython
from coverage.parser import PythonParser


@pytest.mark.parametrize(
    "data",
    [
        b"random_data",
        b"more random data"
    ]
)
def TestOneInput(data):
    """Fuzzer for PythonParser."""
    fdp = atheris.FuzzedDataProvider(data)
    
    t = fdp.ConsumeUnicodeNoSurrogates(1024)
    if not t:
        return
    
    try:
        p = PythonParser(text = t)
        p.parse_source()
    except (NotPython, MemoryError) as e2:
        # Catch Memory error to avoid reporting stack overflows.
        # Catch NotPython issues as these do not signal a bug.
        pass
    except ValueError as e:
        if "source code string cannot contain null bytes" in str(e):
            # Not interesting
            pass
        else:
            raise e


def main():
    """Launch fuzzing campaign."""
    atheris.instrument_all()
    atheris.Setup(sys.argv, TestOneInput, enable_python_coverage=True)
    atheris.Fuzz()


if __name__ == "__main__":
    main()