[asan] add interface function __sanitizer_get_total_unique_coverage; useful for coverage-guided in-process fuzzers

llvm-svn: 222060
This commit is contained in:
Kostya Serebryany
2014-11-14 23:15:55 +00:00
parent 90556aa757
commit 183cb6e35d
4 changed files with 62 additions and 3 deletions

View File

@@ -70,6 +70,9 @@ extern "C" {
// descriptor. Returns -1 on failure, or if coverage dumping is disabled.
// This is intended for use by sandboxing code.
intptr_t __sanitizer_maybe_open_cov_file(const char *name);
// Get the number of total unique covered entities (blocks, edges, calls).
// This can be useful for coverage-directed in-process fuzzers.
uintptr_t __sanitizer_get_total_unique_coverage();
// Annotate the current state of a contiguous container, such as
// std::vector, std::string or similar.

View File

@@ -41,7 +41,9 @@
#include "sanitizer_symbolizer.h"
#include "sanitizer_flags.h"
atomic_uint32_t dump_once_guard; // Ensure that CovDump runs only once.
static atomic_uint32_t dump_once_guard; // Ensure that CovDump runs only once.
static atomic_uintptr_t coverage_counter;
// pc_array is the array containing the covered PCs.
// To make the pc_array thread- and async-signal-safe it has to be large enough.
@@ -201,6 +203,7 @@ void CoverageData::Add(uptr pc) {
CHECK_LT(idx * sizeof(uptr),
atomic_load(&pc_array_size, memory_order_acquire));
pc_array[idx] = pc;
atomic_fetch_add(&coverage_counter, 1, memory_order_relaxed);
}
// Registers a pair caller=>callee.
@@ -228,8 +231,10 @@ void CoverageData::IndirCall(uptr caller, uptr callee, uptr callee_cache[],
for (uptr i = 2; i < cache_size; i++) {
uptr was = 0;
if (atomic_compare_exchange_strong(&atomic_callee_cache[i], &was, callee,
memory_order_seq_cst))
memory_order_seq_cst)) {
atomic_fetch_add(&coverage_counter, 1, memory_order_relaxed);
return;
}
if (was == callee) // Already have this callee.
return;
}
@@ -469,4 +474,8 @@ SANITIZER_INTERFACE_ATTRIBUTE
sptr __sanitizer_maybe_open_cov_file(const char *name) {
return MaybeOpenCovFile(name);
}
SANITIZER_INTERFACE_ATTRIBUTE
uptr __sanitizer_get_total_unique_coverage() {
return atomic_load(&coverage_counter, memory_order_relaxed);
}
} // extern "C"

View File

@@ -0,0 +1,41 @@
// Test __sanitizer_get_total_unique_coverage for caller-callee coverage
// RUN: %clangxx_asan -fsanitize-coverage=4 %s -o %t
// RUN: ASAN_OPTIONS=coverage=1 %run %t
// RUN: rm -f caller-callee*.sancov
//
// REQUIRES: asan-64-bits
#include <sanitizer/common_interface_defs.h>
#include <stdio.h>
#include <assert.h>
int P = 0;
struct Foo {virtual void f() {if (P) printf("Foo::f()\n");}};
struct Foo1 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
struct Foo2 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
Foo *foo[3] = {new Foo, new Foo1, new Foo2};
uintptr_t CheckNewTotalUniqueCoverageIsLargerAndReturnIt(uintptr_t old_total) {
uintptr_t new_total = __sanitizer_get_total_unique_coverage();
assert(new_total > old_total);
return new_total;
}
int main(int argc, char **argv) {
uintptr_t total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(0);
foo[0]->f();
total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total);
foo[1]->f();
total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total);
foo[2]->f();
total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total);
// Ok, called every function once.
// Now call them again from another call site. Should get new coverage.
foo[0]->f();
total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total);
foo[1]->f();
total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total);
foo[2]->f();
total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total);
}

View File

@@ -13,6 +13,8 @@
// https://code.google.com/p/address-sanitizer/issues/detail?id=263
// XFAIL: android
#include "sanitizer/common_interface_defs.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
@@ -29,8 +31,12 @@ int G[4];
int main(int argc, char **argv) {
fprintf(stderr, "PID: %d\n", getpid());
for (int i = 1; i < argc; i++) {
if (!strcmp(argv[i], "foo"))
if (!strcmp(argv[i], "foo")) {
uintptr_t old_coverage = __sanitizer_get_total_unique_coverage();
foo();
uintptr_t new_coverage = __sanitizer_get_total_unique_coverage();
assert(new_coverage > old_coverage);
}
if (!strcmp(argv[i], "bar"))
bar();
}