mirror of
https://github.com/RPCSX/llvm.git
synced 2025-02-24 15:12:36 +00:00
[libFuzzer] add ShrinkValueProfileTest, move code around, NFC
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@283286 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
ef350f2eb3
commit
d4d50f6f47
@ -117,6 +117,70 @@ void TracePC::PrintCoverage() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Value profile.
|
||||||
|
// We keep track of various values that affect control flow.
|
||||||
|
// These values are inserted into a bit-set-based hash map.
|
||||||
|
// Every new bit in the map is treated as a new coverage.
|
||||||
|
//
|
||||||
|
// For memcmp/strcmp/etc the interesting value is the length of the common
|
||||||
|
// prefix of the parameters.
|
||||||
|
// For cmp instructions the interesting value is a XOR of the parameters.
|
||||||
|
// The interesting value is mixed up with the PC and is then added to the map.
|
||||||
|
|
||||||
|
void TracePC::AddValueForMemcmp(void *caller_pc, const void *s1, const void *s2,
|
||||||
|
size_t n) {
|
||||||
|
if (!n) return;
|
||||||
|
size_t Len = std::min(n, (size_t)32);
|
||||||
|
const uint8_t *A1 = reinterpret_cast<const uint8_t *>(s1);
|
||||||
|
const uint8_t *A2 = reinterpret_cast<const uint8_t *>(s2);
|
||||||
|
size_t I = 0;
|
||||||
|
for (; I < Len; I++)
|
||||||
|
if (A1[I] != A2[I])
|
||||||
|
break;
|
||||||
|
size_t PC = reinterpret_cast<size_t>(caller_pc);
|
||||||
|
size_t Idx = I;
|
||||||
|
// if (I < Len)
|
||||||
|
// Idx += __builtin_popcountl((A1[I] ^ A2[I])) - 1;
|
||||||
|
TPC.HandleValueProfile((PC & 4095) | (Idx << 12));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TracePC::AddValueForStrcmp(void *caller_pc, const char *s1, const char *s2,
|
||||||
|
size_t n) {
|
||||||
|
if (!n) return;
|
||||||
|
size_t Len = std::min(n, (size_t)32);
|
||||||
|
const uint8_t *A1 = reinterpret_cast<const uint8_t *>(s1);
|
||||||
|
const uint8_t *A2 = reinterpret_cast<const uint8_t *>(s2);
|
||||||
|
size_t I = 0;
|
||||||
|
for (; I < Len; I++)
|
||||||
|
if (A1[I] != A2[I] || A1[I] == 0)
|
||||||
|
break;
|
||||||
|
size_t PC = reinterpret_cast<size_t>(caller_pc);
|
||||||
|
size_t Idx = I;
|
||||||
|
// if (I < Len && A1[I])
|
||||||
|
// Idx += __builtin_popcountl((A1[I] ^ A2[I])) - 1;
|
||||||
|
TPC.HandleValueProfile((PC & 4095) | (Idx << 12));
|
||||||
|
}
|
||||||
|
|
||||||
|
ATTRIBUTE_TARGET_POPCNT
|
||||||
|
static void AddValueForCmp(void *PCptr, uint64_t Arg1, uint64_t Arg2) {
|
||||||
|
if (Arg1 == Arg2)
|
||||||
|
return;
|
||||||
|
uintptr_t PC = reinterpret_cast<uintptr_t>(PCptr);
|
||||||
|
uint64_t ArgDistance = __builtin_popcountl(Arg1 ^ Arg2) - 1; // [0,63]
|
||||||
|
uintptr_t Idx = (PC & 4095) | (ArgDistance << 12);
|
||||||
|
TPC.HandleValueProfile(Idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void AddValueForSingleVal(void *PCptr, uintptr_t Val) {
|
||||||
|
if (!Val) return;
|
||||||
|
uintptr_t PC = reinterpret_cast<uintptr_t>(PCptr);
|
||||||
|
uint64_t ArgDistance = __builtin_popcountl(Val) - 1; // [0,63]
|
||||||
|
uintptr_t Idx = (PC & 4095) | (ArgDistance << 12);
|
||||||
|
TPC.HandleValueProfile(Idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace fuzzer
|
} // namespace fuzzer
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -136,4 +200,47 @@ void __sanitizer_cov_trace_pc_indir(uintptr_t Callee) {
|
|||||||
uintptr_t PC = (uintptr_t)__builtin_return_address(0);
|
uintptr_t PC = (uintptr_t)__builtin_return_address(0);
|
||||||
fuzzer::TPC.HandleCallerCallee(PC, Callee);
|
fuzzer::TPC.HandleCallerCallee(PC, Callee);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: this one will not be used with the newest clang. Remove it.
|
||||||
|
__attribute__((visibility("default")))
|
||||||
|
void __sanitizer_cov_trace_cmp(uint64_t SizeAndType, uint64_t Arg1,
|
||||||
|
uint64_t Arg2) {
|
||||||
|
fuzzer::AddValueForCmp(__builtin_return_address(0), Arg1, Arg2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__attribute__((visibility("default")))
|
||||||
|
void __sanitizer_cov_trace_cmp8(uint64_t Arg1, int64_t Arg2) {
|
||||||
|
fuzzer::AddValueForCmp(__builtin_return_address(0), Arg1, Arg2);
|
||||||
|
}
|
||||||
|
__attribute__((visibility("default")))
|
||||||
|
void __sanitizer_cov_trace_cmp4(uint32_t Arg1, int32_t Arg2) {
|
||||||
|
fuzzer::AddValueForCmp(__builtin_return_address(0), Arg1, Arg2);
|
||||||
|
}
|
||||||
|
__attribute__((visibility("default")))
|
||||||
|
void __sanitizer_cov_trace_cmp2(uint16_t Arg1, int16_t Arg2) {
|
||||||
|
fuzzer::AddValueForCmp(__builtin_return_address(0), Arg1, Arg2);
|
||||||
|
}
|
||||||
|
__attribute__((visibility("default")))
|
||||||
|
void __sanitizer_cov_trace_cmp1(uint8_t Arg1, int8_t Arg2) {
|
||||||
|
fuzzer::AddValueForCmp(__builtin_return_address(0), Arg1, Arg2);
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((visibility("default")))
|
||||||
|
void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) {
|
||||||
|
// TODO(kcc): support value profile here.
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((visibility("default")))
|
||||||
|
void __sanitizer_cov_trace_div4(uint32_t Val) {
|
||||||
|
fuzzer::AddValueForSingleVal(__builtin_return_address(0), Val);
|
||||||
|
}
|
||||||
|
__attribute__((visibility("default")))
|
||||||
|
void __sanitizer_cov_trace_div8(uint64_t Val) {
|
||||||
|
fuzzer::AddValueForSingleVal(__builtin_return_address(0), Val);
|
||||||
|
}
|
||||||
|
__attribute__((visibility("default")))
|
||||||
|
void __sanitizer_cov_trace_gep(uintptr_t Idx) {
|
||||||
|
fuzzer::AddValueForSingleVal(__builtin_return_address(0), Idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
|
@ -62,6 +62,11 @@ class TracePC {
|
|||||||
|
|
||||||
bool HasFeature(size_t Idx) { return CounterMap.Get(Idx); }
|
bool HasFeature(size_t Idx) { return CounterMap.Get(Idx); }
|
||||||
|
|
||||||
|
void AddValueForMemcmp(void *caller_pc, const void *s1, const void *s2,
|
||||||
|
size_t n);
|
||||||
|
void AddValueForStrcmp(void *caller_pc, const char *s1, const char *s2,
|
||||||
|
size_t n);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool UseCounters = false;
|
bool UseCounters = false;
|
||||||
bool UseValueProfile = false;
|
bool UseValueProfile = false;
|
||||||
|
@ -251,68 +251,6 @@ static size_t InternalStrnlen(const char *S, size_t MaxLen) {
|
|||||||
return Len;
|
return Len;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Value profile.
|
|
||||||
// We keep track of various values that affect control flow.
|
|
||||||
// These values are inserted into a bit-set-based hash map.
|
|
||||||
// Every new bit in the map is treated as a new coverage.
|
|
||||||
//
|
|
||||||
// For memcmp/strcmp/etc the interesting value is the length of the common
|
|
||||||
// prefix of the parameters.
|
|
||||||
// For cmp instructions the interesting value is a XOR of the parameters.
|
|
||||||
// The interesting value is mixed up with the PC and is then added to the map.
|
|
||||||
|
|
||||||
static void AddValueForMemcmp(void *caller_pc, const void *s1, const void *s2,
|
|
||||||
size_t n) {
|
|
||||||
if (!n) return;
|
|
||||||
size_t Len = std::min(n, (size_t)32);
|
|
||||||
const uint8_t *A1 = reinterpret_cast<const uint8_t *>(s1);
|
|
||||||
const uint8_t *A2 = reinterpret_cast<const uint8_t *>(s2);
|
|
||||||
size_t I = 0;
|
|
||||||
for (; I < Len; I++)
|
|
||||||
if (A1[I] != A2[I])
|
|
||||||
break;
|
|
||||||
size_t PC = reinterpret_cast<size_t>(caller_pc);
|
|
||||||
size_t Idx = I;
|
|
||||||
// if (I < Len)
|
|
||||||
// Idx += __builtin_popcountl((A1[I] ^ A2[I])) - 1;
|
|
||||||
TPC.HandleValueProfile((PC & 4095) | (Idx << 12));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void AddValueForStrcmp(void *caller_pc, const char *s1, const char *s2,
|
|
||||||
size_t n) {
|
|
||||||
if (!n) return;
|
|
||||||
size_t Len = std::min(n, (size_t)32);
|
|
||||||
const uint8_t *A1 = reinterpret_cast<const uint8_t *>(s1);
|
|
||||||
const uint8_t *A2 = reinterpret_cast<const uint8_t *>(s2);
|
|
||||||
size_t I = 0;
|
|
||||||
for (; I < Len; I++)
|
|
||||||
if (A1[I] != A2[I] || A1[I] == 0)
|
|
||||||
break;
|
|
||||||
size_t PC = reinterpret_cast<size_t>(caller_pc);
|
|
||||||
size_t Idx = I;
|
|
||||||
// if (I < Len && A1[I])
|
|
||||||
// Idx += __builtin_popcountl((A1[I] ^ A2[I])) - 1;
|
|
||||||
TPC.HandleValueProfile((PC & 4095) | (Idx << 12));
|
|
||||||
}
|
|
||||||
|
|
||||||
ATTRIBUTE_TARGET_POPCNT
|
|
||||||
static void AddValueForCmp(void *PCptr, uint64_t Arg1, uint64_t Arg2) {
|
|
||||||
if (Arg1 == Arg2)
|
|
||||||
return;
|
|
||||||
uintptr_t PC = reinterpret_cast<uintptr_t>(PCptr);
|
|
||||||
uint64_t ArgDistance = __builtin_popcountl(Arg1 ^ Arg2) - 1; // [0,63]
|
|
||||||
uintptr_t Idx = (PC & 4095) | (ArgDistance << 12);
|
|
||||||
TPC.HandleValueProfile(Idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void AddValueForSingleVal(void *PCptr, uintptr_t Val) {
|
|
||||||
if (!Val) return;
|
|
||||||
uintptr_t PC = reinterpret_cast<uintptr_t>(PCptr);
|
|
||||||
uint64_t ArgDistance = __builtin_popcountl(Val) - 1; // [0,63]
|
|
||||||
uintptr_t Idx = (PC & 4095) | (ArgDistance << 12);
|
|
||||||
TPC.HandleValueProfile(Idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace fuzzer
|
} // namespace fuzzer
|
||||||
|
|
||||||
using fuzzer::TS;
|
using fuzzer::TS;
|
||||||
@ -328,7 +266,7 @@ extern "C" {
|
|||||||
#if LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS
|
#if LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS
|
||||||
void __sanitizer_weak_hook_memcmp(void *caller_pc, const void *s1,
|
void __sanitizer_weak_hook_memcmp(void *caller_pc, const void *s1,
|
||||||
const void *s2, size_t n, int result) {
|
const void *s2, size_t n, int result) {
|
||||||
fuzzer::AddValueForMemcmp(caller_pc, s1, s2, n);
|
fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, n);
|
||||||
if (!RecordingMemcmp) return;
|
if (!RecordingMemcmp) return;
|
||||||
if (result == 0) return; // No reason to mutate.
|
if (result == 0) return; // No reason to mutate.
|
||||||
if (n <= 1) return; // Not interesting.
|
if (n <= 1) return; // Not interesting.
|
||||||
@ -338,7 +276,7 @@ void __sanitizer_weak_hook_memcmp(void *caller_pc, const void *s1,
|
|||||||
|
|
||||||
void __sanitizer_weak_hook_strncmp(void *caller_pc, const char *s1,
|
void __sanitizer_weak_hook_strncmp(void *caller_pc, const char *s1,
|
||||||
const char *s2, size_t n, int result) {
|
const char *s2, size_t n, int result) {
|
||||||
fuzzer::AddValueForStrcmp(caller_pc, s1, s2, n);
|
fuzzer::TPC.AddValueForStrcmp(caller_pc, s1, s2, n);
|
||||||
if (!RecordingMemcmp) return;
|
if (!RecordingMemcmp) return;
|
||||||
if (result == 0) return; // No reason to mutate.
|
if (result == 0) return; // No reason to mutate.
|
||||||
size_t Len1 = fuzzer::InternalStrnlen(s1, n);
|
size_t Len1 = fuzzer::InternalStrnlen(s1, n);
|
||||||
@ -352,7 +290,7 @@ void __sanitizer_weak_hook_strncmp(void *caller_pc, const char *s1,
|
|||||||
|
|
||||||
void __sanitizer_weak_hook_strcmp(void *caller_pc, const char *s1,
|
void __sanitizer_weak_hook_strcmp(void *caller_pc, const char *s1,
|
||||||
const char *s2, int result) {
|
const char *s2, int result) {
|
||||||
fuzzer::AddValueForStrcmp(caller_pc, s1, s2, 64);
|
fuzzer::TPC.AddValueForStrcmp(caller_pc, s1, s2, 64);
|
||||||
if (!RecordingMemcmp) return;
|
if (!RecordingMemcmp) return;
|
||||||
if (result == 0) return; // No reason to mutate.
|
if (result == 0) return; // No reason to mutate.
|
||||||
size_t Len1 = strlen(s1);
|
size_t Len1 = strlen(s1);
|
||||||
@ -386,47 +324,4 @@ void __sanitizer_weak_hook_memmem(void *called_pc, const void *s1, size_t len1,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif // LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS
|
#endif // LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS
|
||||||
|
|
||||||
// TODO: this one will not be used with the newest clang. Remove it.
|
|
||||||
__attribute__((visibility("default")))
|
|
||||||
void __sanitizer_cov_trace_cmp(uint64_t SizeAndType, uint64_t Arg1,
|
|
||||||
uint64_t Arg2) {
|
|
||||||
fuzzer::AddValueForCmp(__builtin_return_address(0), Arg1, Arg2);
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((visibility("default")))
|
|
||||||
void __sanitizer_cov_trace_cmp8(uint64_t Arg1, int64_t Arg2) {
|
|
||||||
fuzzer::AddValueForCmp(__builtin_return_address(0), Arg1, Arg2);
|
|
||||||
}
|
|
||||||
__attribute__((visibility("default")))
|
|
||||||
void __sanitizer_cov_trace_cmp4(uint32_t Arg1, int32_t Arg2) {
|
|
||||||
fuzzer::AddValueForCmp(__builtin_return_address(0), Arg1, Arg2);
|
|
||||||
}
|
|
||||||
__attribute__((visibility("default")))
|
|
||||||
void __sanitizer_cov_trace_cmp2(uint16_t Arg1, int16_t Arg2) {
|
|
||||||
fuzzer::AddValueForCmp(__builtin_return_address(0), Arg1, Arg2);
|
|
||||||
}
|
|
||||||
__attribute__((visibility("default")))
|
|
||||||
void __sanitizer_cov_trace_cmp1(uint8_t Arg1, int8_t Arg2) {
|
|
||||||
fuzzer::AddValueForCmp(__builtin_return_address(0), Arg1, Arg2);
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((visibility("default")))
|
|
||||||
void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) {
|
|
||||||
// TODO(kcc): support value profile here.
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((visibility("default")))
|
|
||||||
void __sanitizer_cov_trace_div4(uint32_t Val) {
|
|
||||||
fuzzer::AddValueForSingleVal(__builtin_return_address(0), Val);
|
|
||||||
}
|
|
||||||
__attribute__((visibility("default")))
|
|
||||||
void __sanitizer_cov_trace_div8(uint64_t Val) {
|
|
||||||
fuzzer::AddValueForSingleVal(__builtin_return_address(0), Val);
|
|
||||||
}
|
|
||||||
__attribute__((visibility("default")))
|
|
||||||
void __sanitizer_cov_trace_gep(uintptr_t Idx) {
|
|
||||||
fuzzer::AddValueForSingleVal(__builtin_return_address(0), Idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
@ -80,7 +80,6 @@ set(Tests
|
|||||||
LeakTest
|
LeakTest
|
||||||
LeakTimeoutTest
|
LeakTimeoutTest
|
||||||
LoadTest
|
LoadTest
|
||||||
MinimizeCorpusTest
|
|
||||||
NullDerefTest
|
NullDerefTest
|
||||||
NullDerefOnEmptyTest
|
NullDerefOnEmptyTest
|
||||||
NthRunCrashTest
|
NthRunCrashTest
|
||||||
@ -98,6 +97,8 @@ set(Tests
|
|||||||
SingleStrcmpTest
|
SingleStrcmpTest
|
||||||
SingleStrncmpTest
|
SingleStrncmpTest
|
||||||
SpamyTest
|
SpamyTest
|
||||||
|
ShrinkControlFlowTest
|
||||||
|
ShrinkValueProfileTest
|
||||||
StrcmpTest
|
StrcmpTest
|
||||||
StrncmpTest
|
StrncmpTest
|
||||||
StrstrTest
|
StrstrTest
|
||||||
|
21
lib/Fuzzer/test/ShrinkValueProfileTest.cpp
Normal file
21
lib/Fuzzer/test/ShrinkValueProfileTest.cpp
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// This file is distributed under the University of Illinois Open Source
|
||||||
|
// License. See LICENSE.TXT for details.
|
||||||
|
|
||||||
|
// Test that we can find the minimal item in the corpus (3 bytes: "FUZ").
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
static volatile uint32_t Sink;
|
||||||
|
|
||||||
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||||
|
if (Size < sizeof(uint32_t)) return 0;
|
||||||
|
uint32_t X;
|
||||||
|
size_t Offset = Size < 8 ? 0 : Size / 2;
|
||||||
|
memcpy(&X, Data + Offset, sizeof(uint32_t));
|
||||||
|
Sink = X == 0xAABBCCDD;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -54,6 +54,6 @@ DSO: INFO: Loaded 3 modules
|
|||||||
DSO: BINGO
|
DSO: BINGO
|
||||||
|
|
||||||
RUN: LLVMFuzzer-SimpleTest-TracePC -exit_on_src_pos=SimpleTest.cpp:17 2>&1 | FileCheck %s --check-prefix=EXIT_ON_SRC_POS
|
RUN: LLVMFuzzer-SimpleTest-TracePC -exit_on_src_pos=SimpleTest.cpp:17 2>&1 | FileCheck %s --check-prefix=EXIT_ON_SRC_POS
|
||||||
RUN: LLVMFuzzer-MinimizeCorpusTest-TracePC -exit_on_src_pos=MinimizeCorpusTest.cpp:23 2>&1 | FileCheck %s --check-prefix=EXIT_ON_SRC_POS
|
RUN: LLVMFuzzer-ShrinkControlFlowTest-TracePC -exit_on_src_pos=ShrinkControlFlowTest.cpp:23 2>&1 | FileCheck %s --check-prefix=EXIT_ON_SRC_POS
|
||||||
EXIT_ON_SRC_POS: INFO: found line matching '{{.*}}', exiting.
|
EXIT_ON_SRC_POS: INFO: found line matching '{{.*}}', exiting.
|
||||||
|
|
||||||
|
@ -8,7 +8,8 @@ set(TracePCTests
|
|||||||
CounterTest
|
CounterTest
|
||||||
CallerCalleeTest
|
CallerCalleeTest
|
||||||
NullDerefTest
|
NullDerefTest
|
||||||
MinimizeCorpusTest
|
ShrinkControlFlowTest
|
||||||
|
ShrinkValueProfileTest
|
||||||
FullCoverageSetTest
|
FullCoverageSetTest
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user