text: // 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;
  }
  