aboutsummaryrefslogtreecommitdiff
path: root/driver/libfuzzer_fuzz_target.cpp
blob: d258e5192f37f2d269b4b0ef3257e34b33aaa4fc (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
// Copyright 2021 Code Intelligence GmbH
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <iostream>

#include "libfuzzer_driver.h"

namespace {
bool is_asan_active = false;
}

extern "C" {
const char *__asan_default_options() {
  is_asan_active = true;
  // LeakSanitizer is not yet supported as it reports too many false positives
  // due to how the JVM GC works.
  // We use a distinguished exit code to recognize ASan crashes in tests.
  // Also specify abort_on_error=0 explicitly since ASan aborts rather than
  // exits on macOS by default, which would cause our exit code to be ignored.
  return "abort_on_error=0,detect_leaks=0,exitcode=76";
}

const char *__ubsan_default_options() {
  // We use a distinguished exit code to recognize UBSan crashes in tests.
  // Also specify abort_on_error=0 explicitly since UBSan aborts rather than
  // exits on macOS by default, which would cause our exit code to be ignored.
  return "abort_on_error=0,exitcode=76";
}
}

namespace {
using Driver = jazzer::LibfuzzerDriver;

std::unique_ptr<Driver> gLibfuzzerDriver;
}  // namespace

extern "C" void driver_cleanup() {
  // Free the libfuzzer driver which triggers a clean JVM shutdown.
  gLibfuzzerDriver.reset(nullptr);
}

// Entry point called by libfuzzer before any LLVMFuzzerTestOneInput(...)
// invocations.
extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) {
  if (is_asan_active) {
    std::cerr << "WARN: Jazzer is not compatible with LeakSanitizer yet. Leaks "
                 "are not reported."
              << std::endl;
  }
  gLibfuzzerDriver = std::make_unique<Driver>(argc, argv);
  std::atexit(&driver_cleanup);
  return 0;
}

// Called by the fuzzer for every fuzzing input.
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, const size_t size) {
  auto result = gLibfuzzerDriver->TestOneInput(data, size);
  if (result != jazzer::RunResult::kOk) {
    // Fuzzer triggered an exception or assertion in Java code. Skip the
    // uninformative libFuzzer stack trace.
    std::cerr << "== libFuzzer crashing input ==\n";
    Driver::libfuzzer_print_crashing_input_();
    // DumpReproducer needs to be called after libFuzzer printed its final
    // stats as otherwise it would report incorrect coverage.
    gLibfuzzerDriver->DumpReproducer(data, size);
    if (result == jazzer::RunResult::kDumpAndContinue) {
      // Continue fuzzing after printing the crashing input.
      return 0;
    }
    // Exit directly without invoking libFuzzer's atexit hook.
    driver_cleanup();
    _Exit(Driver::kErrorExitCode);
  }
  return 0;
}