FuzzerExtFunctionsDlsym.cpp
FuzzerExtFunctionsDlsymWin.cpp
FuzzerExtFunctionsWeak.cpp
+ FuzzerExtraCounters.cpp
FuzzerIO.cpp
FuzzerIOPosix.cpp
FuzzerIOWindows.cpp
#define ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
-#define ATTRIBUTE_NO_SANITIZE_ALL ATTRIBUTE_NO_SANITIZE_ADDRESS ATTRIBUTE_NO_SANITIZE_MEMORY
-
+#if defined(__has_feature)
+# if __has_feature(address_sanitizer)
+# define ATTRIBUTE_NO_SANITIZE_ALL ATTRIBUTE_NO_SANITIZE_ADDRESS
+# elif __has_feature(memory_sanitizer)
+# define ATTRIBUTE_NO_SANITIZE_ALL ATTRIBUTE_NO_SANITIZE_MEMORY
+# else
+# define ATTRIBUTE_NO_SANITIZE_ALL
+# endif
+#else
+# define ATTRIBUTE_NO_SANITIZE_ALL
+#endif
#if LIBFUZZER_WINDOWS
#define ATTRIBUTE_INTERFACE __declspec(dllexport)
inline uint32_t Bswap(uint32_t x) { return __builtin_bswap32(x); }
inline uint64_t Bswap(uint64_t x) { return __builtin_bswap64(x); }
+uint8_t *ExtraCountersBegin();
+uint8_t *ExtraCountersEnd();
+void ClearExtraCounters();
+
} // namespace fuzzer
#endif // LLVM_FUZZER_DEFS_H
--- /dev/null
+//===- FuzzerExtraCounters.cpp - Extra coverage counters ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Extra coverage counters defined by user code.
+//===----------------------------------------------------------------------===//
+
+#include "FuzzerDefs.h"
+
+#if LIBFUZZER_LINUX
+__attribute__((weak)) extern uint8_t __start___libfuzzer_extra_counters;
+__attribute__((weak)) extern uint8_t __stop___libfuzzer_extra_counters;
+
+namespace fuzzer {
+uint8_t *ExtraCountersBegin() { return &__start___libfuzzer_extra_counters; }
+uint8_t *ExtraCountersEnd() { return &__stop___libfuzzer_extra_counters; }
+ATTRIBUTE_NO_SANITIZE_ALL
+void ClearExtraCounters() { // hand-written memset, don't asan-ify.
+ uintptr_t *Beg = reinterpret_cast<uintptr_t*>(ExtraCountersBegin());
+ uintptr_t *End = reinterpret_cast<uintptr_t*>(ExtraCountersEnd());
+ for (; Beg < End; Beg++) {
+ *Beg = 0;
+ __asm__ __volatile__("" : : : "memory");
+ }
+}
+
+} // namespace fuzzer
+
+#else
+// TODO: implement for other platforms.
+namespace fuzzer {
+uint8_t *ExtraCountersBegin() { return nullptr; }
+uint8_t *ExtraCountersEnd() { return nullptr; }
+void ClearExtraCounters() {}
+} // namespace fuzzer
+
+#endif
// The coverage counters and PCs.
// These are declared as global variables named "__sancov_*" to simplify
// experiments with inlined instrumentation.
-alignas(8) ATTRIBUTE_INTERFACE
+alignas(64) ATTRIBUTE_INTERFACE
uint8_t __sancov_trace_pc_guard_8bit_counters[fuzzer::TracePC::kNumPCs];
ATTRIBUTE_INTERFACE
void ResetMaps() {
ValueProfileMap.Reset();
memset(Counters(), 0, GetNumPCs());
+ ClearExtraCounters();
}
void UpdateFeatureSet(size_t CurrentElementIdx, size_t CurrentElementSize);
ValueBitMap ValueProfileMap;
};
-template <class Callback>
-size_t TracePC::CollectFeatures(Callback CB) const {
+template <class Callback> // void Callback(size_t Idx, uint8_t Value);
+ATTRIBUTE_NO_SANITIZE_ALL
+void ForEachNonZeroByte(const uint8_t *Begin, const uint8_t *End,
+ size_t FirstFeature, Callback Handle8bitCounter) {
+ typedef uintptr_t LargeType;
+ const size_t Step = sizeof(LargeType) / sizeof(uint8_t);
+ assert(!(reinterpret_cast<uintptr_t>(Begin) % 64));
+ for (auto P = Begin; P < End; P += Step)
+ if (LargeType Bundle = *reinterpret_cast<const LargeType *>(P))
+ for (size_t I = 0; I < Step; I++, Bundle >>= 8)
+ if (uint8_t V = Bundle & 0xff)
+ Handle8bitCounter(FirstFeature + P - Begin + I, V);
+}
+
+template <class Callback> // bool Callback(size_t Feature)
+ATTRIBUTE_NO_SANITIZE_ALL
+__attribute__((noinline))
+size_t TracePC::CollectFeatures(Callback HandleFeature) const {
size_t Res = 0;
- const size_t Step = 8;
uint8_t *Counters = this->Counters();
- assert(reinterpret_cast<uintptr_t>(Counters) % Step == 0);
size_t N = GetNumPCs();
- N = (N + Step - 1) & ~(Step - 1); // Round up.
- for (size_t Idx = 0; Idx < N; Idx += Step) {
- uint64_t Bundle = *reinterpret_cast<uint64_t*>(&Counters[Idx]);
- if (!Bundle) continue;
- for (size_t i = Idx; i < Idx + Step; i++) {
- uint8_t Counter = (Bundle >> ((i - Idx) * 8)) & 0xff;
- if (!Counter) continue;
- unsigned Bit = 0;
- /**/ if (Counter >= 128) Bit = 7;
- else if (Counter >= 32) Bit = 6;
- else if (Counter >= 16) Bit = 5;
- else if (Counter >= 8) Bit = 4;
- else if (Counter >= 4) Bit = 3;
- else if (Counter >= 3) Bit = 2;
- else if (Counter >= 2) Bit = 1;
- size_t Feature = (i * 8 + Bit);
- if (CB(Feature))
- Res++;
- }
- }
+ auto Handle8bitCounter = [&](size_t Idx, uint8_t Counter) {
+ assert(Counter);
+ unsigned Bit = 0;
+ /**/ if (Counter >= 128) Bit = 7;
+ else if (Counter >= 32) Bit = 6;
+ else if (Counter >= 16) Bit = 5;
+ else if (Counter >= 8) Bit = 4;
+ else if (Counter >= 4) Bit = 3;
+ else if (Counter >= 3) Bit = 2;
+ else if (Counter >= 2) Bit = 1;
+ if (HandleFeature(Idx * 8 + Bit))
+ Res++;
+ };
+
+ ForEachNonZeroByte(Counters, Counters + N, 0, Handle8bitCounter);
+ ForEachNonZeroByte(ExtraCountersBegin(), ExtraCountersEnd(), N * 8,
+ Handle8bitCounter);
+
if (UseValueProfile)
ValueProfileMap.ForEach([&](size_t Idx) {
- if (CB(N * 8 + Idx))
+ if (HandleFeature(N * 8 + Idx))
Res++;
});
return Res;
SwapCmpTest
SwitchTest
Switch2Test
+ TableLookupTest
ThreadedLeakTest
ThreadedTest
TimeoutTest
#include "FuzzerDictionary.h"
#include "FuzzerMerge.h"
#include "FuzzerMutate.h"
+#include "FuzzerTracePC.h"
#include "FuzzerRandom.h"
#include "gtest/gtest.h"
#include <memory>
"STARTED 3 1000\nDONE 3 1 \n",
{"B", "D"}, 3);
}
+
+TEST(Fuzzer, ForEachNonZeroByte) {
+ const size_t N = 64;
+ alignas(64) uint8_t Ar[N + 8] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 2, 0, 0, 0, 0, 0, 0,
+ 0, 0, 3, 0, 4, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 5, 0, 6, 0, 0,
+ 0, 0, 0, 0, 0, 0, 7, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 8,
+ 9, 9, 9, 9, 9, 9, 9, 9,
+ };
+ typedef std::vector<std::pair<size_t, uint8_t> > Vec;
+ Vec Res, Expected;
+ auto CB = [&](size_t Idx, uint8_t V) { Res.push_back({Idx, V}); };
+ ForEachNonZeroByte(Ar, Ar + N, 100, CB);
+ Expected = {{108, 1}, {109, 2}, {118, 3}, {120, 4},
+ {135, 5}, {137, 6}, {146, 7}, {163, 8}};
+ EXPECT_EQ(Res, Expected);
+}
--- /dev/null
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+// Make sure the fuzzer eventually finds all possible values of a variable
+// within a range.
+#include <cstring>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <cassert>
+#include <set>
+
+const size_t N = 1 << 12;
+
+// Define an array of counters that will be understood by libFuzzer
+// as extra coverage signal. The array must be:
+// * uint8_t
+// * aligned by 64
+// * in the section named __libfuzzer_extra_counters.
+// The target code may declare more than one such array.
+//
+// Use either `Counters[Idx] = 1` or `Counters[Idx]++;`
+// depending on whether multiple occurrences of the event 'Idx'
+// is important to distinguish from one occurrence.
+alignas(64) __attribute__((section("__libfuzzer_extra_counters")))
+static uint8_t Counters[N];
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ static std::set<uint16_t> SeenIdx;
+ if (Size != 4) return 0;
+ uint32_t Idx;
+ memcpy(&Idx, Data, 4);
+ Idx %= N;
+ assert(Counters[Idx] == 0); // libFuzzer should reset these between the runs.
+ // Or Counters[Idx]=1 if we don't care how many times this happened.
+ Counters[Idx]++;
+ SeenIdx.insert(Idx);
+ if (SeenIdx.size() == N) {
+ fprintf(stderr, "BINGO: found all values\n");
+ abort();
+ }
+ return 0;
+}
--- /dev/null
+REQUIRES: linux
+
+RUN: not LLVMFuzzer-TableLookupTest -print_final_stats=1 2>&1 | FileCheck %s
+CHECK: BINGO
+// Expecting >= 4096 new_units_added
+CHECK: stat::new_units_added:{{.*[4][0-9][0-9][0-9]}}