aboutsummaryrefslogtreecommitdiff
path: root/driver/coverage_tracker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'driver/coverage_tracker.cpp')
-rw-r--r--driver/coverage_tracker.cpp215
1 files changed, 0 insertions, 215 deletions
diff --git a/driver/coverage_tracker.cpp b/driver/coverage_tracker.cpp
deleted file mode 100644
index 0a576085..00000000
--- a/driver/coverage_tracker.cpp
+++ /dev/null
@@ -1,215 +0,0 @@
-// 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 "coverage_tracker.h"
-
-#include <jni.h>
-
-#include <algorithm>
-#include <memory>
-#include <stdexcept>
-
-#include "absl/strings/str_format.h"
-
-extern "C" void __sanitizer_cov_8bit_counters_init(uint8_t *start,
- uint8_t *end);
-extern "C" void __sanitizer_cov_pcs_init(const uintptr_t *pcs_beg,
- const uintptr_t *pcs_end);
-extern "C" size_t __sanitizer_cov_get_observed_pcs(uintptr_t **pc_entries);
-
-constexpr auto kCoverageMapClass =
- "com/code_intelligence/jazzer/runtime/CoverageMap";
-constexpr auto kByteBufferClass = "java/nio/ByteBuffer";
-constexpr auto kCoverageRecorderClass =
- "com/code_intelligence/jazzer/instrumentor/CoverageRecorder";
-
-// The initial size of the Java coverage map (512 counters).
-constexpr std::size_t kInitialCoverageCountersBufferSize = 1u << 9u;
-// The maximum size of the Java coverage map (1,048,576 counters).
-// Since the memory for the coverage map needs to be allocated contiguously,
-// increasing the maximum size incurs additional memory (but not runtime)
-// overhead for all fuzz targets.
-constexpr std::size_t kMaxCoverageCountersBufferSize = 1u << 20u;
-static_assert(kMaxCoverageCountersBufferSize <=
- std::numeric_limits<jint>::max());
-
-namespace {
-void AssertNoException(JNIEnv &env) {
- if (env.ExceptionCheck()) {
- env.ExceptionDescribe();
- throw std::runtime_error(
- "Java exception occurred in CoverageTracker JNI code");
- }
-}
-} // namespace
-
-namespace jazzer {
-
-uint8_t *CoverageTracker::counters_ = nullptr;
-uint32_t *CoverageTracker::fake_instructions_ = nullptr;
-PCTableEntry *CoverageTracker::pc_entries_ = nullptr;
-
-void CoverageTracker::Setup(JNIEnv &env) {
- if (counters_ != nullptr) {
- throw std::runtime_error(
- "CoverageTracker::Setup must not be called more than once");
- }
- JNINativeMethod coverage_tracker_native_methods[]{
- {(char *)"registerNewCoverageCounters", (char *)"()V",
- (void *)&RegisterNewCoverageCounters},
- };
- jclass coverage_map = env.FindClass(kCoverageMapClass);
- env.RegisterNatives(coverage_map, coverage_tracker_native_methods, 1);
-
- // libFuzzer requires an array containing the instruction addresses associated
- // with the coverage counters registered above. Given that we are
- // instrumenting Java code, we need to synthesize addresses that are known not
- // to conflict with any valid instruction address in native code. Just like
- // atheris we ensure there are no collisions by using the addresses of an
- // allocated buffer. Note: We intentionally never deallocate the allocations
- // made here as they have static lifetime and we can't guarantee they wouldn't
- // be freed before libFuzzer stops using them.
- constexpr std::size_t counters_size = kMaxCoverageCountersBufferSize;
- counters_ = new uint8_t[counters_size];
- Clear();
-
- // Never deallocated, see above.
- fake_instructions_ = new uint32_t[counters_size];
- std::fill(fake_instructions_, fake_instructions_ + counters_size, 0);
-
- // Never deallocated, see above.
- pc_entries_ = new PCTableEntry[counters_size];
- for (std::size_t i = 0; i < counters_size; ++i) {
- pc_entries_[i].PC = reinterpret_cast<uintptr_t>(fake_instructions_ + i);
- // TODO: Label Java PCs corresponding to functions as such.
- pc_entries_[i].PCFlags = 0;
- }
-
- // Register the first batch of coverage counters.
- RegisterNewCoverageCounters(env, nullptr);
-}
-
-void JNICALL CoverageTracker::RegisterNewCoverageCounters(JNIEnv &env,
- jclass cls) {
- jclass coverage_map = env.FindClass(kCoverageMapClass);
- AssertNoException(env);
- jfieldID counters_buffer_id = env.GetStaticFieldID(
- coverage_map, "mem", absl::StrFormat("L%s;", kByteBufferClass).c_str());
- AssertNoException(env);
- jobject counters_buffer =
- env.GetStaticObjectField(coverage_map, counters_buffer_id);
- AssertNoException(env);
-
- jclass byte_buffer = env.FindClass(kByteBufferClass);
- AssertNoException(env);
- jmethodID byte_buffer_capacity_id =
- env.GetMethodID(byte_buffer, "capacity", "()I");
- AssertNoException(env);
- jint old_counters_buffer_size =
- env.CallIntMethod(counters_buffer, byte_buffer_capacity_id);
- AssertNoException(env);
-
- jint new_counters_buffer_size;
- if (old_counters_buffer_size == 0) {
- new_counters_buffer_size = kInitialCoverageCountersBufferSize;
- } else {
- new_counters_buffer_size = 2 * old_counters_buffer_size;
- if (new_counters_buffer_size > kMaxCoverageCountersBufferSize) {
- throw std::runtime_error(
- "Maximal size of the coverage counters buffer exceeded");
- }
- }
-
- jobject new_counters_buffer = env.NewDirectByteBuffer(
- static_cast<void *>(counters_), new_counters_buffer_size);
- AssertNoException(env);
- env.SetStaticObjectField(coverage_map, counters_buffer_id,
- new_counters_buffer);
- AssertNoException(env);
-
- // Register only the new second half of the counters buffer with libFuzzer.
- __sanitizer_cov_8bit_counters_init(counters_ + old_counters_buffer_size,
- counters_ + new_counters_buffer_size);
- __sanitizer_cov_pcs_init(
- (uintptr_t *)(pc_entries_ + old_counters_buffer_size),
- (uintptr_t *)(pc_entries_ + new_counters_buffer_size));
-}
-
-void CoverageTracker::Clear() {
- std::fill(counters_, counters_ + kMaxCoverageCountersBufferSize, 0);
-}
-
-uint8_t *CoverageTracker::GetCoverageCounters() { return counters_; }
-
-void CoverageTracker::RecordInitialCoverage(JNIEnv &env) {
- jclass coverage_recorder = env.FindClass(kCoverageRecorderClass);
- AssertNoException(env);
- jmethodID coverage_recorder_update_covered_ids_with_coverage_map =
- env.GetStaticMethodID(coverage_recorder,
- "updateCoveredIdsWithCoverageMap", "()V");
- AssertNoException(env);
- env.CallStaticVoidMethod(
- coverage_recorder,
- coverage_recorder_update_covered_ids_with_coverage_map);
- AssertNoException(env);
-}
-
-void CoverageTracker::ReplayInitialCoverage(JNIEnv &env) {
- jclass coverage_recorder = env.FindClass(kCoverageRecorderClass);
- AssertNoException(env);
- jmethodID coverage_recorder_update_covered_ids_with_coverage_map =
- env.GetStaticMethodID(coverage_recorder, "replayCoveredIds", "()V");
- AssertNoException(env);
- env.CallStaticVoidMethod(
- coverage_recorder,
- coverage_recorder_update_covered_ids_with_coverage_map);
- AssertNoException(env);
-}
-
-std::string CoverageTracker::ComputeCoverage(JNIEnv &env) {
- uintptr_t *covered_pcs;
- size_t num_covered_pcs = __sanitizer_cov_get_observed_pcs(&covered_pcs);
- std::vector<jint> covered_edge_ids{};
- covered_edge_ids.reserve(num_covered_pcs);
- const uintptr_t first_pc = pc_entries_[0].PC;
- std::for_each(covered_pcs, covered_pcs + num_covered_pcs,
- [&covered_edge_ids, first_pc](const uintptr_t pc) {
- jint edge_id =
- (pc - first_pc) / sizeof(fake_instructions_[0]);
- covered_edge_ids.push_back(edge_id);
- });
- delete[] covered_pcs;
-
- jclass coverage_recorder = env.FindClass(kCoverageRecorderClass);
- AssertNoException(env);
- jmethodID coverage_recorder_compute_file_coverage = env.GetStaticMethodID(
- coverage_recorder, "computeFileCoverage", "([I)Ljava/lang/String;");
- AssertNoException(env);
- jintArray covered_edge_ids_jni = env.NewIntArray(num_covered_pcs);
- AssertNoException(env);
- env.SetIntArrayRegion(covered_edge_ids_jni, 0, num_covered_pcs,
- covered_edge_ids.data());
- AssertNoException(env);
- auto file_coverage_jni = (jstring)(env.CallStaticObjectMethod(
- coverage_recorder, coverage_recorder_compute_file_coverage,
- covered_edge_ids_jni));
- AssertNoException(env);
- auto file_coverage_cstr = env.GetStringUTFChars(file_coverage_jni, nullptr);
- AssertNoException(env);
- std::string file_coverage(file_coverage_cstr);
- env.ReleaseStringUTFChars(file_coverage_jni, file_coverage_cstr);
- AssertNoException(env);
- return file_coverage;
-}
-} // namespace jazzer