Bug 1303757 - Add unified fuzzing interface. r=froydnj
authorChristian Holler (:decoder) <choller@mozilla.com>
Wed, 19 Oct 2016 01:18:12 +0200
changeset 319008 f94ee24c51bd7ee27bf6f9bebd9b2ec3386e5637
parent 319007 60a927b296353edf92aba6ac26ff21ddca93791b
child 319009 24b1342fe710a067ba90b5a2eca5eb3e2b0bf6c1
push id30858
push userryanvm@gmail.com
push dateSun, 23 Oct 2016 17:17:41 +0000
treeherdermozilla-central@a9a41b69f3f9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1303757
milestone52.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1303757 - Add unified fuzzing interface. r=froydnj MozReview-Commit-ID: Dk5ajWlVHQj
tools/fuzzing/interface/FuzzingInterface.cpp
tools/fuzzing/interface/FuzzingInterface.h
tools/fuzzing/interface/moz.build
tools/fuzzing/moz.build
new file mode 100644
--- /dev/null
+++ b/tools/fuzzing/interface/FuzzingInterface.cpp
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Interface implementation for the unified fuzzing interface
+ */
+
+#include "FuzzingInterface.h"
+
+#include "nsNetUtil.h"
+
+namespace mozilla {
+
+#ifdef __AFL_COMPILER
+void afl_interface_stream(const char* testFile, FuzzingTestFuncStream testFunc) {
+    nsresult rv;
+    nsCOMPtr<nsIProperties> dirService =
+      do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
+    MOZ_RELEASE_ASSERT(dirService != nullptr);
+    nsCOMPtr<nsIFile> file;
+    rv = dirService->Get(NS_OS_CURRENT_WORKING_DIR,
+                         NS_GET_IID(nsIFile), getter_AddRefs(file));
+    MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
+    file->AppendNative(nsDependentCString(testFile));
+    while(__AFL_LOOP(1000)) {
+      nsCOMPtr<nsIInputStream> inputStream;
+      rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), file);
+      MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
+      if (!NS_InputStreamIsBuffered(inputStream)) {
+        nsCOMPtr<nsIInputStream> bufStream;
+        rv = NS_NewBufferedInputStream(getter_AddRefs(bufStream),
+                                       inputStream, 1024);
+        MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
+        inputStream = bufStream;
+      }
+      testFunc(inputStream.forget());
+    }
+}
+
+void afl_interface_raw(const char* testFile, FuzzingTestFuncRaw testFunc) {
+    char* buf = NULL;
+
+    while(__AFL_LOOP(1000)) {
+      std::ifstream is;
+      is.open (testFile, std::ios::binary);
+      is.seekg (0, std::ios::end);
+      int len = is.tellg();
+      is.seekg (0, std::ios::beg);
+      MOZ_RELEASE_ASSERT(len >= 0);
+      if (!len) {
+        is.close();
+        continue;
+      }
+      buf = (char*)realloc(buf, len);
+      MOZ_RELEASE_ASSERT(buf);
+      is.read(buf,len);
+      is.close();
+      testFunc((uint8_t*)buf, (size_t)len);
+    }
+
+    free(buf);
+}
+#endif
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/tools/fuzzing/interface/FuzzingInterface.h
@@ -0,0 +1,100 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Interface definitions for the unified fuzzing interface
+ */
+
+#ifndef FuzzingInterface_h__
+#define FuzzingInterface_h__
+
+#include "gtest/gtest.h"
+#include "nsComponentManagerUtils.h"
+#include "nsCOMPtr.h"
+#include "nsIInputStream.h"
+
+#include "nsDirectoryServiceDefs.h"
+#include "nsIDirectoryService.h"
+#include "nsIFile.h"
+#include "nsStreamUtils.h"
+#include "nsStringStream.h"
+
+#include <fstream>
+
+namespace mozilla {
+
+typedef int(*FuzzingTestFuncRaw)(const uint8_t*, size_t);
+typedef int(*FuzzingTestFuncStream)(nsCOMPtr<nsIInputStream>);
+
+#ifdef __AFL_COMPILER
+void afl_interface_stream(const char* testFile, FuzzingTestFuncStream testFunc);
+void afl_interface_raw(const char* testFile, FuzzingTestFuncRaw testFunc);
+
+#define MOZ_AFL_INTERFACE_COMMON(initFunc)                                                    \
+  initFunc(NULL, NULL);                                                                       \
+  char* testFilePtr = getenv("MOZ_FUZZ_TESTFILE");                                            \
+  if (!testFilePtr) {                                                                         \
+    EXPECT_TRUE(false) << "Must specify testfile in MOZ_FUZZ_TESTFILE environment variable."; \
+    return;                                                                                   \
+  }                                                                                           \
+  /* Make a copy of testFilePtr so the testing function can safely call getenv */             \
+  std::string testFile(testFilePtr);
+
+#define MOZ_AFL_INTERFACE_STREAM(initFunc, testFunc, moduleName) \
+  TEST(AFL, moduleName) {                                        \
+    MOZ_AFL_INTERFACE_COMMON(initFunc);                          \
+    ::mozilla::afl_interface_stream(testFile.c_str(), testFunc); \
+  }
+
+#define MOZ_AFL_INTERFACE_RAW(initFunc, testFunc, moduleName)    \
+  TEST(AFL, moduleName) {                                        \
+    MOZ_AFL_INTERFACE_COMMON(initFunc);                          \
+    ::mozilla::afl_interface_raw(testFile.c_str(), testFunc);    \
+  }
+#else
+#define MOZ_AFL_INTERFACE_STREAM(initFunc, testFunc, moduleName) /* Nothing */
+#define MOZ_AFL_INTERFACE_RAW(initFunc, testFunc, moduleName)    /* Nothing */
+#endif
+
+#ifdef LIBFUZZER
+#define MOZ_LIBFUZZER_INTERFACE_STREAM(initFunc, testFunc, moduleName)      \
+  static int LibFuzzerTest##moduleName (const uint8_t *data, size_t size) { \
+    if (size > INT32_MAX)                                                   \
+      return 0;                                                             \
+    nsCOMPtr<nsIInputStream> stream;                                        \
+    nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream),             \
+      (const char*)data, size, NS_ASSIGNMENT_DEPEND);                       \
+    MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));                                   \
+    testFunc(stream.forget());                                              \
+    return 0;                                                               \
+  }                                                                         \
+  static void __attribute__ ((constructor)) LibFuzzerRegister() {           \
+    ::mozilla::LibFuzzerRegistry::getInstance().registerModule(             \
+      #moduleName, initFunc, LibFuzzerTest##moduleName                      \
+    );                                                                      \
+  }
+
+#define MOZ_LIBFUZZER_INTERFACE_RAW(initFunc, testFunc, moduleName)         \
+  static void __attribute__ ((constructor)) LibFuzzerRegister() {           \
+    ::mozilla::LibFuzzerRegistry::getInstance().registerModule(             \
+      #moduleName, initFunc, testFunc                                       \
+    );                                                                      \
+  }
+#else
+#define MOZ_LIBFUZZER_INTERFACE_STREAM(initFunc, testFunc, moduleName) /* Nothing */
+#define MOZ_LIBFUZZER_INTERFACE_RAW(initFunc, testFunc, moduleName)    /* Nothing */
+#endif
+
+#define MOZ_FUZZING_INTERFACE_STREAM(initFunc, testFunc, moduleName) \
+  MOZ_LIBFUZZER_INTERFACE_STREAM(initFunc, testFunc, moduleName);    \
+  MOZ_AFL_INTERFACE_STREAM(initFunc, testFunc, moduleName);
+
+#define MOZ_FUZZING_INTERFACE_RAW(initFunc, testFunc, moduleName)    \
+  MOZ_LIBFUZZER_INTERFACE_RAW(initFunc, testFunc, moduleName);       \
+  MOZ_AFL_INTERFACE_RAW(initFunc, testFunc, moduleName);
+
+} // namespace mozilla
+
+#endif  // FuzzingInterface_h__
new file mode 100644
--- /dev/null
+++ b/tools/fuzzing/interface/moz.build
@@ -0,0 +1,15 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+EXPORTS += [
+    'FuzzingInterface.h',
+]
+
+SOURCES += [
+    'FuzzingInterface.cpp',
+]
+
+FINAL_LIBRARY = 'xul-gtest'
new file mode 100644
--- /dev/null
+++ b/tools/fuzzing/moz.build
@@ -0,0 +1,14 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+DIRS += [
+  'interface',
+]
+
+if CONFIG['LIBFUZZER']:
+  DIRS += [
+    'libfuzzer',
+  ]