contrib/fuzz/manifest.cc
author FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
Thu, 23 Aug 2018 12:24:41 +0900
changeset 40092 58786930ea27
parent 40089 3418f83c8874
child 40100 ca4a32d0a4d6
permissions -rw-r--r--
tests: use environment variable indirectly Using environment variable directly in heredoc python code will cause syntax error at checking module importation by import-checker.py strictly, because "$varname" is invalid in Python syntax. "$varname" becomes valid after environment variable substitution by shell at writing text into file. Current import-checker.py overlooks code fragment changed in this patch, because of a restriction below for a line starting code fragment. - filename must be specified before limit mark NG: cat <<EOF > FILE.py OK: cat > FILE.py <<EOF import-checker.py itself is fixed in subsequent patch.

#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
lm = lazymanifest(mdata)
try:
  # 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);
	PyEval_EvalCode(code, globals, locals);
	Py_DECREF(code);
	Py_DECREF(locals);
	Py_DECREF(mtext);
	return 0; // Non-zero return values are reserved for future use.
}
}