contrib/fuzz/fncache.cc
author Augie Fackler <augie@google.com>
Wed, 09 Oct 2019 20:49:39 -0700
changeset 43152 b37dd26935ee
child 43859 8766728dbce6
permissions -rw-r--r--
fuzz: new fuzzer for fncache-related functions Not all of these are strictly fncache-related, but they all have th same signature and similar-enough behavior that we may as well fuzz them together. No obvious bugs for once, but these felt like they were just complicated enough to cover. Differential Revision: https://phab.mercurial-scm.org/D7033

#include <Python.h>
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>

#include "pyutil.h"

#include <iostream>
#include <string>

extern "C" {

static PyCodeObject *code;

extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv)
{
	contrib::initpy(*argv[0]);
	code = (PyCodeObject *)Py_CompileString(R"py(
from parsers import (
    isasciistr,
    asciilower,
    asciiupper,
    encodedir,
    pathencode,
    lowerencode,
)

try:
    for fn in (
        isasciistr,
        asciilower,
        asciiupper,
        encodedir,
        pathencode,
        lowerencode,
    ):
        try:
            fn(data)
        except UnicodeDecodeError:
            pass  # some functions emit this exception
        except AttributeError:
            # pathencode needs hashlib, which fails to import because the time
            # module fails to import. We should try and fix that some day, but
            # for now we at least get coverage on non-hashencoded codepaths.
            if fn != pathencode:
                raise
        # uncomment this for debugging exceptions
        # except Exception as e:
        #     raise Exception('%r: %r' % (fn, e))
except Exception as e:
    pass
    # uncomment this print if you're editing this Python code
    # to debug failures.
    # print(e)
)py",
	                                        "fuzzer", Py_file_input);
	if (!code) {
		std::cerr << "failed to compile Python code!" << std::endl;
	}
	return 0;
}

int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
{
	PyObject *mtext =
	    PyBytes_FromStringAndSize((const char *)Data, (Py_ssize_t)Size);
	PyObject *locals = PyDict_New();
	PyDict_SetItemString(locals, "data", mtext);
	PyObject *res = PyEval_EvalCode(code, contrib::pyglobals(), locals);
	if (!res) {
		PyErr_Print();
	}
	Py_XDECREF(res);
	Py_DECREF(locals);
	Py_DECREF(mtext);
	return 0; // Non-zero return values are reserved for future use.
}
}