summaryrefslogtreecommitdiffstats
path: root/tools/fuzzing/interface/harness/FuzzerRunner.cpp
blob: fc2094aa59bf170a625e3d52fcab63702362151d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
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