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
92
93
94
95
96
97
98
99
100
101
102
103
|
// 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 "com_code_intelligence_jazzer_driver_FuzzTargetRunner.h"
#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);
}
// This symbol is defined by sanitizers if linked into Jazzer or in
// sanitizer_symbols.cpp if no sanitizer is used.
extern "C" void __sanitizer_set_death_callback(void (*)());
// We apply a patch to libFuzzer to make it call this function instead of
// __sanitizer_set_death_callback to pass us the death callback.
extern "C" [[maybe_unused]] void __jazzer_set_death_callback(
void (*callback)()) {
jazzer::AbstractLibfuzzerDriver::libfuzzer_print_crashing_input_ = callback;
__sanitizer_set_death_callback([]() {
jazzer::DumpJvmStackTraces();
jazzer::AbstractLibfuzzerDriver::libfuzzer_print_crashing_input_();
// Ideally, we would be able to call driver_cleanup here to perform a
// graceful shutdown of the JVM. However, doing this directly results in a
// nested bug report by ASan or UBSan, likely because something about the
// stack/thread context in which they generate reports is incompatible with
// the JVM shutdown process. use_sigaltstack=0 does not help though, so this
// might be on us. The alternative of calling driver_cleanup in a new thread
// and joining on it results in an endless wait in DestroyJavaVM, even when
// the main thread is detached beforehand - it is not clear why.
});
}
void Java_com_code_1intelligence_jazzer_driver_FuzzTargetRunner_printCrashingInput(
JNIEnv *, jclass) {
jazzer::AbstractLibfuzzerDriver::libfuzzer_print_crashing_input_();
}
void Java_com_code_1intelligence_jazzer_driver_FuzzTargetRunner__1Exit(
JNIEnv *, jclass, jint exit_code) {
_Exit(exit_code);
}
// 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) {
return gLibfuzzerDriver->TestOneInput(data, size);
}
|