[libFuzzer] more agressive value profiling and CMP tracing for switch statements

llvm-svn: 352107
This commit is contained in:
Kostya Serebryany 2019-01-24 21:08:54 +00:00
parent b432369f6b
commit 360bf5ff58
3 changed files with 57 additions and 11 deletions

View File

@ -536,24 +536,44 @@ void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) {
uint64_t N = Cases[0];
uint64_t ValSizeInBits = Cases[1];
uint64_t *Vals = Cases + 2;
// Skip the most common and the most boring case.
if (Vals[N - 1] < 256 && Val < 256)
// Skip the most common and the most boring case: all switch values are small.
// We may want to skip this at compile-time, but it will make the
// instrumentation less general.
if (Vals[N - 1] < 256)
return;
// Also skip small inputs values, they won't give good signal.
if (Val < 256)
return;
uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
size_t i;
uint64_t Token = 0;
uint64_t Smaller = 0;
uint64_t Larger = ~(uint64_t)0;
// Find two switch values such that Smaller < Val < Larger.
// Use 0 and 0xfff..f as the defaults.
for (i = 0; i < N; i++) {
Token = Val ^ Vals[i];
if (Val < Vals[i])
if (Val < Vals[i]) {
Larger = Vals[i];
break;
}
if (Val > Vals[i]) Smaller = Vals[i];
}
if (ValSizeInBits == 16)
fuzzer::TPC.HandleCmp(PC + i, static_cast<uint16_t>(Token), (uint16_t)(0));
else if (ValSizeInBits == 32)
fuzzer::TPC.HandleCmp(PC + i, static_cast<uint32_t>(Token), (uint32_t)(0));
else
fuzzer::TPC.HandleCmp(PC + i, Token, (uint64_t)(0));
// Apply HandleCmp to {Val,Smaller} and {Val, Larger},
// use i as the PC modifier for HandleCmp.
if (ValSizeInBits == 16) {
fuzzer::TPC.HandleCmp(PC + 2 * i, static_cast<uint16_t>(Val),
(uint16_t)(Smaller));
fuzzer::TPC.HandleCmp(PC + 2 * i + 1, static_cast<uint16_t>(Val),
(uint16_t)(Larger));
} else if (ValSizeInBits == 32) {
fuzzer::TPC.HandleCmp(PC + 2 * i, static_cast<uint32_t>(Val),
(uint32_t)(Smaller));
fuzzer::TPC.HandleCmp(PC + 2 * i + 1, static_cast<uint32_t>(Val),
(uint32_t)(Larger));
} else {
fuzzer::TPC.HandleCmp(PC + 2*i, Val, Smaller);
fuzzer::TPC.HandleCmp(PC + 2*i + 1, Val, Larger);
}
}
ATTRIBUTE_INTERFACE

View File

@ -0,0 +1,24 @@
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// Simple test for a fuzzer. The fuzzer must find the interesting switch value.
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
static volatile int Sink;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
uint32_t v;
if (Size < 100) return 0;
memcpy(&v, Data + Size / 2, sizeof(v));
switch(v) {
case 0x47524159: abort();
case 0x52474220: abort();
default:;
}
return 0;
}

View File

@ -2,5 +2,7 @@ UNSUPPORTED: ios
CHECK: BINGO
RUN: %cpp_compiler %S/SwitchTest.cpp -o %t-SwitchTest
RUN: %cpp_compiler %S/Switch2Test.cpp -o %t-Switch2Test
RUN: %cpp_compiler %S/Switch3Test.cpp -o %t-Switch3Test
RUN: not %run %t-SwitchTest -use_cmp=0 -use_value_profile=1 -runs=100000000 -seed=1 2>&1 | FileCheck %s
RUN: not %run %t-Switch2Test -use_cmp=0 -use_value_profile=1 -runs=100000000 -seed=1 2>&1 | FileCheck %s
RUN: not %run %t-Switch3Test -use_cmp=0 -use_value_profile=1 -runs=100000000 -seed=1 2>&1