chromium/third_party/fuzztest/src/fuzztest/internal/coverage.cc

// Copyright 2022 Google LLC
//
// 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 "./fuzztest/internal/coverage.h"

#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <memory>
#include <type_traits>

#include "absl/base/attributes.h"
#include "absl/strings/str_format.h"
#include "absl/types/span.h"
#include "./fuzztest/internal/flag_name.h"
#include "./fuzztest/internal/logging.h"
#include "./fuzztest/internal/table_of_recent_compares.h"

// IMPORTANT: Almost all functions (e.g. Update()) in this file will
// be called during coverage instrumentation callbacks.
//
// AVOID LIBRARY FUNCTION CALLS from here:
// Library functions can be instrumented, which cause reentrancy issues.

namespace fuzztest::internal {
namespace {

// We use this function in instrumentation callbacks instead of library
// functions (like `absl::bit_width`) in order to avoid having potentially
// instrumented code in the callback.
constexpr uint8_t BitWidth(uint8_t x) {}

}  // namespace

// We want to make the tracing codes as light-weight as possible, so
// we disabled most sanitizers. Some may not be necessary but we don't
// want any one of them in the tracing codes so it's fine.
#define FUZZTEST_INTERNAL_NOSANITIZE

// TODO(b/311658540):
//
// When integrated with Centipede, the execution coverage is
// created/used by only the mutators in the engine or runner process
// (for auto-dictionary mutation). Since each mutator runs in its
// thread without the need to share the coverage information with
// others, we can make this singleton thread_local, otherwise there
// can be data-races when accessing the instance from multiple
// Centipede shards.
//
// When running without Centipede, the singleton instance is updated
// by test threads during the test execution. Thus we cannot make it
// thread_local as it would skip coverage information in the threads
// other than the thread running the property function, but we then
// suffer from the race conditions.  This issue is hard to fix, but as
// we are fully switching to the Centipede integration soon, we will
// leave the issue as-is.
#ifdef FUZZTEST_USE_CENTIPEDE
thread_local ExecutionCoverage *execution_coverage_instance = nullptr;
#else
ExecutionCoverage *execution_coverage_instance =;
#endif

void SetExecutionCoverage(ExecutionCoverage *value) {}

ExecutionCoverage* GetExecutionCoverage() {}

FUZZTEST_INTERNAL_NOSANITIZE void ExecutionCoverage::UpdateCmpMap(
    size_t index, uint8_t hamming_dist, uint8_t absolute_dist) {}

void ExecutionCoverage::UpdateMaxStack(uintptr_t PC) {}

// Coverage only available in Clang, but only for Linux.
// iOS and Windows and Android might not have what we need.
#if defined(__clang__) && defined(__linux__) && !defined(__ANDROID__)
namespace {
// Use clang's vector extensions. This way it will implement with whatever the
// platform supports.
// Using a large vector size allows the compiler to choose the largest
// vectorized instruction it can for the architecture.
// Eg, it will use 4 xmm's per iteration in westmere, 2 ymm's in haswell, and 1
// zmm when avx512 is enabled.
Vector __attribute__((vector_size(64)));

constexpr size_t kVectorSize =;
FUZZTEST_INTERNAL_NOSANITIZE bool UpdateVectorized(
    const uint8_t *execution_data, uint8_t *corpus_data, size_t size,
    size_t offset_to_align) {}
}  // namespace

CorpusCoverage::CorpusCoverage(size_t map_size) {}

CorpusCoverage::~CorpusCoverage() {}

bool CorpusCoverage::Update(ExecutionCoverage* execution_coverage) {}

#else  // __clang__ && __linux__

// On other compilers we just need it to build, but we know we don't have any
// instrumentation.
CorpusCoverage::CorpusCoverage(size_t map_size)
    : corpus_map_size_(0), corpus_map_(nullptr) {}
CorpusCoverage::~CorpusCoverage() {}
bool CorpusCoverage::Update(ExecutionCoverage* execution_coverage) {
  return false;
}

#endif  // __clang__ && __linux__

}  // namespace fuzztest::internal

#if !defined(FUZZTEST_COMPATIBILITY_MODE) && !defined(FUZZTEST_USE_CENTIPEDE)
// Sanitizer Coverage hooks.

// The instrumentation runtime calls back the following function at startup,
// where [start,end) is the array of 8-bit counters created for the current DSO.
extern "C" void __sanitizer_cov_8bit_counters_init(uint8_t* start,
                                                   uint8_t* stop) {}

// This function should have no external library dependencies to prevent
// accidental coverage instrumentation.
template <int data_size>
ABSL_ATTRIBUTE_ALWAYS_INLINE      // To make __builtin_return_address(0) work.
    FUZZTEST_INTERNAL_NOSANITIZE  // To skip arg1 - arg2 overflow.
    void
    TraceCmp(uint64_t arg1, uint64_t arg2, uint8_t argsize_bit,
             uintptr_t PC =
                 reinterpret_cast<uintptr_t>(__builtin_return_address(0))) {}

// Use NO_SANITIZE_MEMORY and ADDRESS to skip possible errors on reading buffer.
FUZZTEST_INTERNAL_NOSANITIZE
static size_t InternalStrnlen(const char *s, size_t n) {}

FUZZTEST_INTERNAL_NOSANITIZE
static size_t InternalStrlen(const char *s1, const char *s2) {}

FUZZTEST_INTERNAL_NOSANITIZE
static void TraceMemCmp(const uint8_t *s1, const uint8_t *s2, size_t n,
                        int result) {}

extern "C" {
void __sanitizer_cov_trace_const_cmp1(uint8_t Arg1, uint8_t Arg2) {}
void __sanitizer_cov_trace_const_cmp2(uint16_t Arg1, uint16_t Arg2) {}
void __sanitizer_cov_trace_const_cmp4(uint32_t Arg1, uint32_t Arg2) {}
void __sanitizer_cov_trace_const_cmp8(uint64_t Arg1, uint64_t Arg2) {}
void __sanitizer_cov_trace_cmp1(uint8_t Arg1, uint8_t Arg2) {}
void __sanitizer_cov_trace_cmp2(uint16_t Arg1, uint16_t Arg2) {}
void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2) {}
void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2) {}

FUZZTEST_INTERNAL_NOSANITIZE
void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) {}

FUZZTEST_INTERNAL_NOSANITIZE
void __sanitizer_weak_hook_strcasecmp(void *, const char *s1, const char *s2,
                                      int result) {}

FUZZTEST_INTERNAL_NOSANITIZE
void __sanitizer_weak_hook_memcmp(void *, const void *s1, const void *s2,
                                  size_t n, int result) {}

FUZZTEST_INTERNAL_NOSANITIZE
void __sanitizer_weak_hook_strncmp(void *, const char *s1, const char *s2,
                                   size_t n, int result) {}

FUZZTEST_INTERNAL_NOSANITIZE
void __sanitizer_weak_hook_strcmp(void *, const char *s1, const char *s2,
                                  int result) {}

FUZZTEST_INTERNAL_NOSANITIZE
void __sanitizer_weak_hook_strncasecmp(void *caller_pc, const char *s1,
                                       const char *s2, size_t n, int result) {}
}

#endif  // !defined(FUZZTEST_COMPATIBILITY_MODE) &&
        // !defined(FUZZTEST_USE_CENTIPEDE)