Patchwork D7033: fuzz: new fuzzer for fncache-related functions

login
register
mail settings
Submitter phabricator
Date Oct. 9, 2019, 4:19 p.m.
Message ID <differential-rev-PHID-DREV-2cjjgfmtwvqpguezjtl3-req@mercurial-scm.org>
Download mbox | patch
Permalink /patch/42140/
State Superseded
Headers show

Comments

phabricator - Oct. 9, 2019, 4:19 p.m.
durin42 created this revision.
Herald added subscribers: mercurial-devel, mjpieters.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  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.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D7033

AFFECTED FILES
  contrib/fuzz/Makefile
  contrib/fuzz/fncache.cc

CHANGE DETAILS




To: durin42, #hg-reviewers
Cc: mjpieters, mercurial-devel

Patch

diff --git a/contrib/fuzz/fncache.cc b/contrib/fuzz/fncache.cc
new file mode 100644
--- /dev/null
+++ b/contrib/fuzz/fncache.cc
@@ -0,0 +1,78 @@ 
+#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.
+}
+}
diff --git a/contrib/fuzz/Makefile b/contrib/fuzz/Makefile
--- a/contrib/fuzz/Makefile
+++ b/contrib/fuzz/Makefile
@@ -113,6 +113,14 @@ 
 	  -lFuzzingEngine `$$OUT/sanpy/bin/python-config --ldflags` \
 	  -o $$OUT/dirs_fuzzer
 
+fncache_fuzzer: fncache.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 fncache.cc \
+	  manifest.o charencode.o parsers.o dirs.o pathencode.o revlog.o pyutil.o \
+	  -lFuzzingEngine `$$OUT/sanpy/bin/python-config --ldflags` \
+	  -o $$OUT/fncache_fuzzer
+
 manifest_corpus.zip:
 	python manifest_corpus.py $$OUT/manifest_fuzzer_seed_corpus.zip
 
@@ -163,6 +171,6 @@ 
 	  mpatch \
 	  xdiff
 
-oss-fuzz: bdiff_fuzzer mpatch_fuzzer mpatch_corpus.zip xdiff_fuzzer dirs_fuzzer manifest_fuzzer manifest_corpus.zip revlog_fuzzer revlog_corpus.zip dirstate_fuzzer dirstate_corpus.zip fm1readmarkers_fuzzer fm1readmarkers_corpus.zip
+oss-fuzz: bdiff_fuzzer mpatch_fuzzer mpatch_corpus.zip xdiff_fuzzer dirs_fuzzer fncache_fuzzer manifest_fuzzer manifest_corpus.zip revlog_fuzzer revlog_corpus.zip dirstate_fuzzer dirstate_corpus.zip fm1readmarkers_fuzzer fm1readmarkers_corpus.zip
 
 .PHONY: all clean oss-fuzz