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