summaryrefslogtreecommitdiffstats
path: root/tools/fuzzing/interface
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:44:51 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:44:51 +0000
commit9e3c08db40b8916968b9f30096c7be3f00ce9647 (patch)
treea68f146d7fa01f0134297619fbe7e33db084e0aa /tools/fuzzing/interface
parentInitial commit. (diff)
downloadthunderbird-9e3c08db40b8916968b9f30096c7be3f00ce9647.tar.xz
thunderbird-9e3c08db40b8916968b9f30096c7be3f00ce9647.zip
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--tools/fuzzing/interface/FuzzingInterface.cpp30
-rw-r--r--tools/fuzzing/interface/FuzzingInterface.h115
-rw-r--r--tools/fuzzing/interface/FuzzingInterfaceStream.cpp54
-rw-r--r--tools/fuzzing/interface/FuzzingInterfaceStream.h90
-rw-r--r--tools/fuzzing/interface/harness/FuzzerRunner.cpp91
-rw-r--r--tools/fuzzing/interface/harness/FuzzerRunner.h24
-rw-r--r--tools/fuzzing/interface/harness/FuzzerTestHarness.h256
-rw-r--r--tools/fuzzing/interface/harness/moz.build16
-rw-r--r--tools/fuzzing/interface/moz.build32
9 files changed, 708 insertions, 0 deletions
diff --git a/tools/fuzzing/interface/FuzzingInterface.cpp b/tools/fuzzing/interface/FuzzingInterface.cpp
new file mode 100644
index 0000000000..f06ca68656
--- /dev/null
+++ b/tools/fuzzing/interface/FuzzingInterface.cpp
@@ -0,0 +1,30 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+/*
+ * Common code for the unified fuzzing interface
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include "FuzzingInterface.h"
+
+namespace mozilla {
+
+#ifdef JS_STANDALONE
+static bool fuzzing_verbose = !!getenv("MOZ_FUZZ_LOG");
+void fuzzing_log(const char* aFmt, ...) {
+ if (fuzzing_verbose) {
+ va_list ap;
+ va_start(ap, aFmt);
+ vfprintf(stderr, aFmt, ap);
+ va_end(ap);
+ }
+}
+#else
+LazyLogModule gFuzzingLog("nsFuzzing");
+#endif
+
+} // namespace mozilla
diff --git a/tools/fuzzing/interface/FuzzingInterface.h b/tools/fuzzing/interface/FuzzingInterface.h
new file mode 100644
index 0000000000..792f0809ec
--- /dev/null
+++ b/tools/fuzzing/interface/FuzzingInterface.h
@@ -0,0 +1,115 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 <fstream>
+
+#ifdef LIBFUZZER
+# include "FuzzerExtFunctions.h"
+#endif
+
+#include "FuzzerRegistry.h"
+#include "mozilla/Assertions.h"
+
+#ifndef JS_STANDALONE
+# include "mozilla/Logging.h"
+#endif
+
+namespace mozilla {
+
+#ifdef JS_STANDALONE
+void fuzzing_log(const char* aFmt, ...);
+# define MOZ_LOG_EXPAND_ARGS(...) __VA_ARGS__
+
+# define FUZZING_LOG(args) fuzzing_log(MOZ_LOG_EXPAND_ARGS args);
+#else
+extern LazyLogModule gFuzzingLog;
+
+# define FUZZING_LOG(args) \
+ MOZ_LOG(mozilla::gFuzzingLog, mozilla::LogLevel::Verbose, args)
+#endif // JS_STANDALONE
+
+typedef int (*FuzzingTestFuncRaw)(const uint8_t*, size_t);
+
+#ifdef AFLFUZZ
+
+static int 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);
+
+ return 0;
+}
+
+# define MOZ_AFL_INTERFACE_COMMON() \
+ char* testFilePtr = getenv("MOZ_FUZZ_TESTFILE"); \
+ if (!testFilePtr) { \
+ fprintf(stderr, \
+ "Must specify testfile in MOZ_FUZZ_TESTFILE environment " \
+ "variable.\n"); \
+ return 1; \
+ } \
+ /* Make a copy of testFilePtr so the testing function can safely call \
+ * getenv \
+ */ \
+ std::string testFile(testFilePtr);
+
+# define MOZ_AFL_INTERFACE_RAW(initFunc, testFunc, moduleName) \
+ static int afl_fuzz_##moduleName(const uint8_t* data, size_t size) { \
+ MOZ_RELEASE_ASSERT(data == NULL && size == 0); \
+ MOZ_AFL_INTERFACE_COMMON(); \
+ return ::mozilla::afl_interface_raw(testFile.c_str(), testFunc); \
+ } \
+ static void __attribute__((constructor)) AFLRegister##moduleName() { \
+ ::mozilla::FuzzerRegistry::getInstance().registerModule( \
+ #moduleName, initFunc, afl_fuzz_##moduleName); \
+ }
+#else
+# define MOZ_AFL_INTERFACE_RAW(initFunc, testFunc, moduleName) /* Nothing */
+#endif // AFLFUZZ
+
+#ifdef LIBFUZZER
+# define MOZ_LIBFUZZER_INTERFACE_RAW(initFunc, testFunc, moduleName) \
+ static void __attribute__((constructor)) LibFuzzerRegister##moduleName() { \
+ ::mozilla::FuzzerRegistry::getInstance().registerModule( \
+ #moduleName, initFunc, testFunc); \
+ }
+#else
+# define MOZ_LIBFUZZER_INTERFACE_RAW(initFunc, testFunc, \
+ moduleName) /* Nothing */
+#endif
+
+#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__
diff --git a/tools/fuzzing/interface/FuzzingInterfaceStream.cpp b/tools/fuzzing/interface/FuzzingInterfaceStream.cpp
new file mode 100644
index 0000000000..f2c5c891e9
--- /dev/null
+++ b/tools/fuzzing/interface/FuzzingInterfaceStream.cpp
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 "nsIFile.h"
+#include "nsIPrefService.h"
+#include "nsIProperties.h"
+
+#include "FuzzingInterfaceStream.h"
+
+#include "mozilla/Assertions.h"
+
+#ifndef JS_STANDALONE
+# include "nsNetUtil.h"
+#endif
+
+namespace mozilla {
+
+#ifdef AFLFUZZ
+
+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.forget(), 1024);
+ MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
+ inputStream = bufStream;
+ }
+ testFunc(inputStream.forget());
+ }
+}
+
+#endif
+
+} // namespace mozilla
diff --git a/tools/fuzzing/interface/FuzzingInterfaceStream.h b/tools/fuzzing/interface/FuzzingInterfaceStream.h
new file mode 100644
index 0000000000..1542020794
--- /dev/null
+++ b/tools/fuzzing/interface/FuzzingInterfaceStream.h
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 with streaming
+ * support
+ */
+
+#ifndef FuzzingInterfaceStream_h__
+#define FuzzingInterfaceStream_h__
+
+#ifdef JS_STANDALONE
+# error "FuzzingInterfaceStream.h cannot be used in JS standalone builds."
+#endif
+
+#include "gtest/gtest.h"
+#include "nsComponentManagerUtils.h"
+#include "nsCOMPtr.h"
+#include "nsIInputStream.h"
+
+#include "nsDirectoryServiceDefs.h"
+#include "nsStreamUtils.h"
+#include "nsStringStream.h"
+
+#include <fstream>
+
+#include "FuzzingInterface.h"
+
+namespace mozilla {
+
+typedef int (*FuzzingTestFuncStream)(nsCOMPtr<nsIInputStream>);
+
+#ifdef AFLFUZZ
+void afl_interface_stream(const char* testFile, FuzzingTestFuncStream testFunc);
+
+# define MOZ_AFL_INTERFACE_COMMON(initFunc) \
+ if (initFunc) initFunc(NULL, NULL); \
+ char* testFilePtr = getenv("MOZ_FUZZ_TESTFILE"); \
+ if (!testFilePtr) { \
+ fprintf(stderr, \
+ "Must specify testfile in MOZ_FUZZ_TESTFILE environment " \
+ "variable.\n"); \
+ 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); \
+ }
+#else
+# define MOZ_AFL_INTERFACE_STREAM(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), \
+ Span((const char*)data, size), \
+ NS_ASSIGNMENT_DEPEND); \
+ MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); \
+ testFunc(stream.forget()); \
+ return 0; \
+ } \
+ static void __attribute__((constructor)) LibFuzzerRegister##moduleName() { \
+ ::mozilla::FuzzerRegistry::getInstance().registerModule( \
+ #moduleName, initFunc, LibFuzzerTest##moduleName); \
+ }
+#else
+# define MOZ_LIBFUZZER_INTERFACE_STREAM(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);
+
+} // namespace mozilla
+
+#endif // FuzzingInterfaceStream_h__
diff --git a/tools/fuzzing/interface/harness/FuzzerRunner.cpp b/tools/fuzzing/interface/harness/FuzzerRunner.cpp
new file mode 100644
index 0000000000..fc2094aa59
--- /dev/null
+++ b/tools/fuzzing/interface/harness/FuzzerRunner.cpp
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * * 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/. */
+
+#include <cstdlib>
+
+#include "FuzzerRunner.h"
+#include "mozilla/Attributes.h"
+#include "prenv.h"
+
+#include "FuzzerTestHarness.h"
+
+namespace mozilla {
+
+// We use a static var 'fuzzerRunner' defined in nsAppRunner.cpp.
+// fuzzerRunner is initialized to nullptr but if this file is linked in,
+// then fuzzerRunner will be set here indicating that
+// we want to call into either LibFuzzer's main or the AFL entrypoint.
+class _InitFuzzer {
+ public:
+ _InitFuzzer() { fuzzerRunner = new FuzzerRunner(); }
+ void InitXPCOM() { mScopedXPCOM = new ScopedXPCOM("Fuzzer"); }
+ void DeinitXPCOM() {
+ if (mScopedXPCOM) delete mScopedXPCOM;
+ mScopedXPCOM = nullptr;
+ }
+
+ private:
+ ScopedXPCOM* mScopedXPCOM;
+} InitLibFuzzer;
+
+static void DeinitXPCOM() { InitLibFuzzer.DeinitXPCOM(); }
+
+int FuzzerRunner::Run(int* argc, char*** argv) {
+ /*
+ * libFuzzer uses exit() calls in several places instead of returning,
+ * so the destructor of ScopedXPCOM is not called in some cases.
+ * For fuzzing, this does not make a difference, but in debug builds
+ * when running a single testcase, this causes an assertion when destroying
+ * global linked lists. For this reason, we allocate ScopedXPCOM on the heap
+ * using the global InitLibFuzzer class, combined with an atexit call to
+ * destroy the ScopedXPCOM instance again.
+ */
+ InitLibFuzzer.InitXPCOM();
+ std::atexit(DeinitXPCOM);
+
+ const char* fuzzerEnv = getenv("FUZZER");
+
+ if (!fuzzerEnv) {
+ fprintf(stderr,
+ "Must specify fuzzing target in FUZZER environment variable\n");
+ exit(1);
+ }
+
+ std::string moduleNameStr(fuzzerEnv);
+ FuzzerFunctions funcs =
+ FuzzerRegistry::getInstance().getModuleFunctions(moduleNameStr);
+ FuzzerInitFunc initFunc = funcs.first;
+ FuzzerTestingFunc testingFunc = funcs.second;
+ if (initFunc) {
+ int ret = initFunc(argc, argv);
+ if (ret) {
+ fprintf(stderr, "Fuzzing Interface: Error: Initialize callback failed\n");
+ exit(1);
+ }
+ }
+
+ if (!testingFunc) {
+ fprintf(stderr, "Fuzzing Interface: Error: No testing callback found\n");
+ exit(1);
+ }
+
+#ifdef LIBFUZZER
+ int ret = mFuzzerDriver(argc, argv, testingFunc);
+#else
+ // For AFL, testingFunc points to the entry function we need.
+ int ret = testingFunc(NULL, 0);
+#endif
+
+ InitLibFuzzer.DeinitXPCOM();
+ return ret;
+}
+
+#ifdef LIBFUZZER
+void FuzzerRunner::setParams(LibFuzzerDriver aDriver) {
+ mFuzzerDriver = aDriver;
+}
+#endif
+
+} // namespace mozilla
diff --git a/tools/fuzzing/interface/harness/FuzzerRunner.h b/tools/fuzzing/interface/harness/FuzzerRunner.h
new file mode 100644
index 0000000000..6b19e751cd
--- /dev/null
+++ b/tools/fuzzing/interface/harness/FuzzerRunner.h
@@ -0,0 +1,24 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * * 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/. */
+
+#include "FuzzerRegistry.h"
+
+namespace mozilla {
+
+class FuzzerRunner {
+ public:
+ int Run(int* argc, char*** argv);
+
+#ifdef LIBFUZZER
+ void setParams(LibFuzzerDriver aDriver);
+
+ private:
+ LibFuzzerDriver mFuzzerDriver;
+#endif
+};
+
+extern FuzzerRunner* fuzzerRunner;
+
+} // namespace mozilla
diff --git a/tools/fuzzing/interface/harness/FuzzerTestHarness.h b/tools/fuzzing/interface/harness/FuzzerTestHarness.h
new file mode 100644
index 0000000000..d7bb1064cf
--- /dev/null
+++ b/tools/fuzzing/interface/harness/FuzzerTestHarness.h
@@ -0,0 +1,256 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+/*
+ * Test harness for XPCOM objects, providing a scoped XPCOM initializer,
+ * nsCOMPtr, nsRefPtr, do_CreateInstance, do_GetService, ns(Auto|C|)String,
+ * and stdio.h/stdlib.h.
+ */
+
+#ifndef FuzzerTestHarness_h__
+#define FuzzerTestHarness_h__
+
+#include "mozilla/ArrayUtils.h"
+#include "mozilla/Attributes.h"
+
+#include "prenv.h"
+#include "nsComponentManagerUtils.h"
+#include "nsServiceManagerUtils.h"
+#include "nsCOMPtr.h"
+#include "nsString.h"
+#include "nsAppDirectoryServiceDefs.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsDirectoryServiceUtils.h"
+#include "nsIDirectoryService.h"
+#include "nsIFile.h"
+#include "nsIObserverService.h"
+#include "nsIServiceManager.h"
+#include "nsXULAppAPI.h"
+#include "mozilla/AppShutdown.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+namespace {
+
+static uint32_t gFailCount = 0;
+
+/**
+ * Prints the given failure message and arguments using printf, prepending
+ * "TEST-UNEXPECTED-FAIL " for the benefit of the test harness and
+ * appending "\n" to eliminate having to type it at each call site.
+ */
+MOZ_FORMAT_PRINTF(1, 2) void fail(const char* msg, ...) {
+ va_list ap;
+
+ printf("TEST-UNEXPECTED-FAIL | ");
+
+ va_start(ap, msg);
+ vprintf(msg, ap);
+ va_end(ap);
+
+ putchar('\n');
+ ++gFailCount;
+}
+
+//-----------------------------------------------------------------------------
+
+class ScopedXPCOM final : public nsIDirectoryServiceProvider2 {
+ public:
+ NS_DECL_ISUPPORTS
+
+ explicit ScopedXPCOM(const char* testName,
+ nsIDirectoryServiceProvider* dirSvcProvider = nullptr)
+ : mDirSvcProvider(dirSvcProvider) {
+ mTestName = testName;
+ printf("Running %s tests...\n", mTestName);
+
+ nsresult rv = NS_InitXPCOM(&mServMgr, nullptr, this);
+ if (NS_FAILED(rv)) {
+ fail("NS_InitXPCOM returned failure code 0x%" PRIx32,
+ static_cast<uint32_t>(rv));
+ mServMgr = nullptr;
+ return;
+ }
+ }
+
+ ~ScopedXPCOM() {
+ // If we created a profile directory, we need to remove it.
+ if (mProfD) {
+ mozilla::AppShutdown::AdvanceShutdownPhase(
+ mozilla::ShutdownPhase::AppShutdownNetTeardown);
+ mozilla::AppShutdown::AdvanceShutdownPhase(
+ mozilla::ShutdownPhase::AppShutdownTeardown);
+ mozilla::AppShutdown::AdvanceShutdownPhase(
+ mozilla::ShutdownPhase::AppShutdown);
+ mozilla::AppShutdown::AdvanceShutdownPhase(
+ mozilla::ShutdownPhase::AppShutdownQM);
+ mozilla::AppShutdown::AdvanceShutdownPhase(
+ mozilla::ShutdownPhase::AppShutdownTelemetry);
+
+ if (NS_FAILED(mProfD->Remove(true))) {
+ NS_WARNING("Problem removing profile directory");
+ }
+
+ mProfD = nullptr;
+ }
+
+ if (mServMgr) {
+ NS_RELEASE(mServMgr);
+ nsresult rv = NS_ShutdownXPCOM(nullptr);
+ if (NS_FAILED(rv)) {
+ fail("XPCOM shutdown failed with code 0x%" PRIx32,
+ static_cast<uint32_t>(rv));
+ exit(1);
+ }
+ }
+
+ printf("Finished running %s tests.\n", mTestName);
+ }
+
+ already_AddRefed<nsIFile> GetProfileDirectory() {
+ if (mProfD) {
+ nsCOMPtr<nsIFile> copy = mProfD;
+ return copy.forget();
+ }
+
+ // Create a unique temporary folder to use for this test.
+ // Note that runcppunittests.py will run tests with a temp
+ // directory as the cwd, so just put something under that.
+ nsCOMPtr<nsIFile> profD;
+ nsresult rv = NS_GetSpecialDirectory(NS_OS_CURRENT_PROCESS_DIR,
+ getter_AddRefs(profD));
+ NS_ENSURE_SUCCESS(rv, nullptr);
+
+ rv = profD->Append(u"cpp-unit-profd"_ns);
+ NS_ENSURE_SUCCESS(rv, nullptr);
+
+ rv = profD->CreateUnique(nsIFile::DIRECTORY_TYPE, 0755);
+ NS_ENSURE_SUCCESS(rv, nullptr);
+
+ mProfD = profD;
+ return profD.forget();
+ }
+
+ already_AddRefed<nsIFile> GetGREDirectory() {
+ if (mGRED) {
+ nsCOMPtr<nsIFile> copy = mGRED;
+ return copy.forget();
+ }
+
+ char* env = PR_GetEnv("MOZ_XRE_DIR");
+ nsCOMPtr<nsIFile> greD;
+ if (env) {
+ NS_NewLocalFile(NS_ConvertUTF8toUTF16(env), false, getter_AddRefs(greD));
+ }
+
+ mGRED = greD;
+ return greD.forget();
+ }
+
+ already_AddRefed<nsIFile> GetGREBinDirectory() {
+ if (mGREBinD) {
+ nsCOMPtr<nsIFile> copy = mGREBinD;
+ return copy.forget();
+ }
+
+ nsCOMPtr<nsIFile> greD = GetGREDirectory();
+ if (!greD) {
+ return greD.forget();
+ }
+ greD->Clone(getter_AddRefs(mGREBinD));
+
+#ifdef XP_MACOSX
+ nsAutoCString leafName;
+ mGREBinD->GetNativeLeafName(leafName);
+ if (leafName.EqualsLiteral("Resources")) {
+ mGREBinD->SetNativeLeafName("MacOS"_ns);
+ }
+#endif
+
+ nsCOMPtr<nsIFile> copy = mGREBinD;
+ return copy.forget();
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //// nsIDirectoryServiceProvider
+
+ NS_IMETHODIMP GetFile(const char* aProperty, bool* _persistent,
+ nsIFile** _result) override {
+ // If we were supplied a directory service provider, ask it first.
+ if (mDirSvcProvider && NS_SUCCEEDED(mDirSvcProvider->GetFile(
+ aProperty, _persistent, _result))) {
+ return NS_OK;
+ }
+
+ // Otherwise, the test harness provides some directories automatically.
+ if (0 == strcmp(aProperty, NS_APP_USER_PROFILE_50_DIR) ||
+ 0 == strcmp(aProperty, NS_APP_USER_PROFILE_LOCAL_50_DIR) ||
+ 0 == strcmp(aProperty, NS_APP_PROFILE_LOCAL_DIR_STARTUP)) {
+ nsCOMPtr<nsIFile> profD = GetProfileDirectory();
+ NS_ENSURE_TRUE(profD, NS_ERROR_FAILURE);
+
+ nsCOMPtr<nsIFile> clone;
+ nsresult rv = profD->Clone(getter_AddRefs(clone));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ *_persistent = true;
+ clone.forget(_result);
+ return NS_OK;
+ } else if (0 == strcmp(aProperty, NS_GRE_DIR)) {
+ nsCOMPtr<nsIFile> greD = GetGREDirectory();
+ NS_ENSURE_TRUE(greD, NS_ERROR_FAILURE);
+
+ *_persistent = true;
+ greD.forget(_result);
+ return NS_OK;
+ } else if (0 == strcmp(aProperty, NS_GRE_BIN_DIR)) {
+ nsCOMPtr<nsIFile> greBinD = GetGREBinDirectory();
+ NS_ENSURE_TRUE(greBinD, NS_ERROR_FAILURE);
+
+ *_persistent = true;
+ greBinD.forget(_result);
+ return NS_OK;
+ }
+
+ return NS_ERROR_FAILURE;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //// nsIDirectoryServiceProvider2
+
+ NS_IMETHODIMP GetFiles(const char* aProperty,
+ nsISimpleEnumerator** _enum) override {
+ // If we were supplied a directory service provider, ask it first.
+ nsCOMPtr<nsIDirectoryServiceProvider2> provider =
+ do_QueryInterface(mDirSvcProvider);
+ if (provider && NS_SUCCEEDED(provider->GetFiles(aProperty, _enum))) {
+ return NS_OK;
+ }
+
+ return NS_ERROR_FAILURE;
+ }
+
+ private:
+ const char* mTestName;
+ nsIServiceManager* mServMgr;
+ nsCOMPtr<nsIDirectoryServiceProvider> mDirSvcProvider;
+ nsCOMPtr<nsIFile> mProfD;
+ nsCOMPtr<nsIFile> mGRED;
+ nsCOMPtr<nsIFile> mGREBinD;
+};
+
+NS_IMPL_QUERY_INTERFACE(ScopedXPCOM, nsIDirectoryServiceProvider,
+ nsIDirectoryServiceProvider2)
+
+NS_IMETHODIMP_(MozExternalRefCountType)
+ScopedXPCOM::AddRef() { return 2; }
+
+NS_IMETHODIMP_(MozExternalRefCountType)
+ScopedXPCOM::Release() { return 1; }
+
+} // namespace
+
+#endif // FuzzerTestHarness_h__
diff --git a/tools/fuzzing/interface/harness/moz.build b/tools/fuzzing/interface/harness/moz.build
new file mode 100644
index 0000000000..0eff84c8aa
--- /dev/null
+++ b/tools/fuzzing/interface/harness/moz.build
@@ -0,0 +1,16 @@
+# -*- 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/.
+
+Library("fuzzer-runner")
+
+SOURCES += [
+ "FuzzerRunner.cpp",
+]
+EXPORTS += [
+ "FuzzerRunner.h",
+]
+
+FINAL_LIBRARY = "xul"
diff --git a/tools/fuzzing/interface/moz.build b/tools/fuzzing/interface/moz.build
new file mode 100644
index 0000000000..8a51007174
--- /dev/null
+++ b/tools/fuzzing/interface/moz.build
@@ -0,0 +1,32 @@
+# -*- 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/.
+
+Library("fuzzer-interface")
+
+EXPORTS += [
+ "FuzzingInterface.h",
+]
+
+SOURCES += [
+ "FuzzingInterface.cpp",
+]
+
+if CONFIG["JS_STANDALONE"]:
+ FINAL_LIBRARY = "js"
+else:
+ EXPORTS += [
+ "FuzzingInterfaceStream.h",
+ ]
+
+ SOURCES += [
+ "FuzzingInterfaceStream.cpp",
+ ]
+
+ DIRS += [
+ "harness",
+ ]
+
+ FINAL_LIBRARY = "xul-gtest"