blob: d258e5192f37f2d269b4b0ef3257e34b33aaa4fc [file] [log] [blame]
// 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;
}