diff --git a/contrib/fuzz/Makefile b/contrib/fuzz/Makefile --- a/contrib/fuzz/Makefile +++ b/contrib/fuzz/Makefile @@ -12,6 +12,11 @@ $(CXX) $(CXXFLAGS) -std=c++17 \ -I../../mercurial -c -o fuzzutil-oss-fuzz.o fuzzutil.cc +pyutil.o: pyutil.cc pyutil.h + $(CXX) $(CXXFLAGS) -g -O1 \ + `$$OUT/sanpy/bin/python-config --cflags` \ + -I../../mercurial -c -o pyutil.o pyutil.cc + bdiff.o: ../../mercurial/bdiff.c $(CC) $(CFLAGS) -fsanitize=fuzzer-no-link,address -c -o bdiff.o \ ../../mercurial/bdiff.c @@ -108,11 +113,11 @@ -I../../mercurial \ -c -o revlog.o ../../mercurial/cext/revlog.c -manifest_fuzzer: sanpy manifest.cc manifest.o charencode.o parsers.o dirs.o pathencode.o revlog.o +manifest_fuzzer: sanpy manifest.cc manifest.o charencode.o parsers.o dirs.o pathencode.o revlog.o pyutil.o $(CXX) $(CXXFLAGS) `$$OUT/sanpy/bin/python-config --cflags` \ -Wno-register -Wno-macro-redefined \ -I../../mercurial manifest.cc \ - manifest.o charencode.o parsers.o dirs.o pathencode.o revlog.o \ + manifest.o charencode.o parsers.o dirs.o pathencode.o revlog.o pyutil.o \ -lFuzzingEngine `$$OUT/sanpy/bin/python-config --ldflags` \ -o $$OUT/manifest_fuzzer diff --git a/contrib/fuzz/manifest.cc b/contrib/fuzz/manifest.cc --- a/contrib/fuzz/manifest.cc +++ b/contrib/fuzz/manifest.cc @@ -3,43 +3,17 @@ #include #include +#include "pyutil.h" + #include extern "C" { -/* TODO: use Python 3 for this fuzzing? */ -PyMODINIT_FUNC initparsers(void); - -static char cpypath[8192] = "\0"; - static PyCodeObject *code; -static PyObject *mainmod; -static PyObject *globals; 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); - setenv("PYTHONNOUSERSITE", "1", 1); - /* prevent Python from looking up users in the fuzz environment */ - setenv("PYTHONUSERBASE", cpypath, 1); - Py_SetPythonHome(cpypath); - Py_InitializeEx(0); - initparsers(); + contrib::initpy(*argv[0]); code = (PyCodeObject *)Py_CompileString(R"py( from parsers import lazymanifest try: @@ -60,8 +34,6 @@ # print e )py", "fuzzer", Py_file_input); - mainmod = PyImport_AddModule("__main__"); - globals = PyModule_GetDict(mainmod); return 0; } @@ -71,7 +43,7 @@ PyBytes_FromStringAndSize((const char *)Data, (Py_ssize_t)Size); PyObject *locals = PyDict_New(); PyDict_SetItemString(locals, "mdata", mtext); - PyObject *res = PyEval_EvalCode(code, globals, locals); + PyObject *res = PyEval_EvalCode(code, contrib::pyglobals(), locals); if (!res) { PyErr_Print(); } diff --git a/contrib/fuzz/pyutil.h b/contrib/fuzz/pyutil.h new file mode 100644 --- /dev/null +++ b/contrib/fuzz/pyutil.h @@ -0,0 +1,9 @@ +#include + +namespace contrib +{ + +void initpy(const char *cselfpath); +PyObject *pyglobals(); + +} /* namespace contrib */ diff --git a/contrib/fuzz/pyutil.cc b/contrib/fuzz/pyutil.cc new file mode 100644 --- /dev/null +++ b/contrib/fuzz/pyutil.cc @@ -0,0 +1,49 @@ +#include "pyutil.h" + +#include + +namespace contrib +{ + +static char cpypath[8192] = "\0"; + +static PyObject *mainmod; +static PyObject *globals; + +/* TODO: use Python 3 for this fuzzing? */ +PyMODINIT_FUNC initparsers(void); + +void initpy(const char *cselfpath) +{ + 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(cselfpath); + 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); + setenv("PYTHONNOUSERSITE", "1", 1); + /* prevent Python from looking up users in the fuzz environment */ + setenv("PYTHONUSERBASE", cpypath, 1); + Py_SetPythonHome(cpypath); + Py_InitializeEx(0); + mainmod = PyImport_AddModule("__main__"); + globals = PyModule_GetDict(mainmod); + initparsers(); +} + +PyObject *pyglobals() +{ + return globals; +} + +} // namespace contrib