view contrib/fuzz/manifest.cc @ 40100:ca4a32d0a4d6

fuzz: report error if Python code raised exception I think that's what we wanted to do, given the most of the code block is surrounded by try-except. 'lazymanifest(mdata)' is moved to the try block as it can fail.
author Yuya Nishihara <yuya@tcha.org>
date Tue, 09 Oct 2018 07:46:01 +0900
parents 3418f83c8874
children adfe4bb53a47
line wrap: on
line source

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

#include <string>

extern "C" {

/* TODO: use Python 3 for this fuzzing? */
PyMODINIT_FUNC initparsers(void);

static char cpypath[8192] = "\0";

extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv)
{
	const std::string subdir = "/sanpy/lib/python2.7";
	/* HACK ALERT: we need a full Python installation built without
	   pymalloc and with ASAN, so we dump one in
	   $OUT/sanpy/lib/python2.7. This helps us wire that up. */
	std::string selfpath(*argv[0]);
	std::string pypath;
	auto pos = selfpath.rfind("/");
	if (pos == std::string::npos) {
		char wd[8192];
		getcwd(wd, 8192);
		pypath = std::string(wd) + subdir;
	} else {
		pypath = selfpath.substr(0, pos) + subdir;
	}
	strncpy(cpypath, pypath.c_str(), pypath.size());
	setenv("PYTHONPATH", cpypath, 1);
	Py_SetPythonHome(cpypath);
	Py_InitializeEx(0);
	return 0;
}

int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
{
	initparsers();
	PyObject *mtext =
	    PyBytes_FromStringAndSize((const char *)Data, (Py_ssize_t)Size);
	PyObject *mainmod = PyImport_AddModule("__main__");
	PyObject *globals = PyModule_GetDict(mainmod);
	PyObject *locals = PyDict_New();
	PyDict_SetItemString(locals, "mdata", mtext);
	PyCodeObject *code =
	    (PyCodeObject *)Py_CompileString(R"py(
from parsers import lazymanifest
try:
  lm = lazymanifest(mdata)
  # iterate the whole thing, which causes the code to fully parse
  # every line in the manifest
  list(lm.iterentries())
  lm[b'xyzzy'] = (b'\0' * 20, 'x')
  # do an insert, text should change
  assert lm.text() != mdata, "insert should change text and didn't: %r %r" % (lm.text(), mdata)
  del lm[b'xyzzy']
  # should be back to the same
  assert lm.text() == mdata, "delete should have restored text but didn't: %r %r" % (lm.text(), mdata)
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);
	PyObject *res = PyEval_EvalCode(code, globals, locals);
	if (!res) {
		PyErr_Print();
	}
	Py_XDECREF(res);
	Py_DECREF(code);
	Py_DECREF(locals);
	Py_DECREF(mtext);
	return 0; // Non-zero return values are reserved for future use.
}
}