From 183cb6e35db5f9c5f35f0fcb82295db2e8e77057 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Fri, 14 Nov 2014 23:15:55 +0000 Subject: [PATCH] [asan] add interface function __sanitizer_get_total_unique_coverage; useful for coverage-guided in-process fuzzers llvm-svn: 222060 --- .../include/sanitizer/common_interface_defs.h | 3 ++ .../sanitizer_common/sanitizer_coverage_libcdep.cc | 13 +++++-- .../Linux/coverage-caller-callee-total-count.cc | 41 ++++++++++++++++++++++ compiler-rt/test/asan/TestCases/Linux/coverage.cc | 8 ++++- 4 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 compiler-rt/test/asan/TestCases/Linux/coverage-caller-callee-total-count.cc diff --git a/compiler-rt/include/sanitizer/common_interface_defs.h b/compiler-rt/include/sanitizer/common_interface_defs.h index deb053d..9cb5ad8 100644 --- a/compiler-rt/include/sanitizer/common_interface_defs.h +++ b/compiler-rt/include/sanitizer/common_interface_defs.h @@ -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. diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep.cc index edcaa7f..d7da6c9 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep.cc @@ -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" diff --git a/compiler-rt/test/asan/TestCases/Linux/coverage-caller-callee-total-count.cc b/compiler-rt/test/asan/TestCases/Linux/coverage-caller-callee-total-count.cc new file mode 100644 index 0000000..0201425 --- /dev/null +++ b/compiler-rt/test/asan/TestCases/Linux/coverage-caller-callee-total-count.cc @@ -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 +#include +#include +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); +} diff --git a/compiler-rt/test/asan/TestCases/Linux/coverage.cc b/compiler-rt/test/asan/TestCases/Linux/coverage.cc index 741c667..f6eb0ae 100644 --- a/compiler-rt/test/asan/TestCases/Linux/coverage.cc +++ b/compiler-rt/test/asan/TestCases/Linux/coverage.cc @@ -13,6 +13,8 @@ // https://code.google.com/p/address-sanitizer/issues/detail?id=263 // XFAIL: android +#include "sanitizer/common_interface_defs.h" +#include #include #include #include @@ -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(); } -- 2.7.4