Index: compiler-rt/trunk/include/sanitizer/coverage_interface.h =================================================================== --- compiler-rt/trunk/include/sanitizer/coverage_interface.h +++ compiler-rt/trunk/include/sanitizer/coverage_interface.h @@ -41,13 +41,6 @@ // Some of the entries in *data will be zero. uintptr_t __sanitizer_get_coverage_guards(uintptr_t **data); - // Set *data to the growing buffer with covered PCs and return the size - // of the buffer. The entries are never zero. - // When only unique pcs are collected, the size is equal to - // __sanitizer_get_total_unique_coverage. - // WARNING: EXPERIMENTAL API. - uintptr_t __sanitizer_get_coverage_pc_buffer(uintptr_t **data); - // The coverage instrumentation may optionally provide imprecise counters. // Rather than exposing the counter values to the user we instead map // the counters to a bitset. @@ -65,6 +58,15 @@ // __sanitizer_get_number_of_counters bytes long and 8-aligned. uintptr_t __sanitizer_update_counter_bitset_and_clear_counters(uint8_t *bitset); + + // EXPERIMENTAL API + // Set allocated buffer to record new coverage PCs as they are executed. + // Buffer length is specified in uptrs. + void __sanitizer_set_coverage_pc_buffer(uintptr_t *buffer, uintptr_t length); + // Number of pcs recorded in the buffer. + // Reset by __sanitizer_reset_coverage(); + uintptr_t __sanitizer_get_coverage_pc_buffer_pos(); + #ifdef __cplusplus } // extern "C" #endif Index: compiler-rt/trunk/lib/asan/asan_win_dll_thunk.cc =================================================================== --- compiler-rt/trunk/lib/asan/asan_win_dll_thunk.cc +++ compiler-rt/trunk/lib/asan/asan_win_dll_thunk.cc @@ -320,7 +320,7 @@ INTERFACE_FUNCTION(__sanitizer_cov_with_check) INTERFACE_FUNCTION(__sanitizer_get_allocated_size) INTERFACE_FUNCTION(__sanitizer_get_coverage_guards) -INTERFACE_FUNCTION(__sanitizer_get_coverage_pc_buffer) +INTERFACE_FUNCTION(__sanitizer_get_coverage_pc_buffer_pos) INTERFACE_FUNCTION(__sanitizer_get_current_allocated_bytes) INTERFACE_FUNCTION(__sanitizer_get_estimated_allocated_size) INTERFACE_FUNCTION(__sanitizer_get_free_bytes) @@ -338,6 +338,7 @@ INTERFACE_FUNCTION(__sanitizer_get_number_of_counters) INTERFACE_FUNCTION(__sanitizer_update_counter_bitset_and_clear_counters) INTERFACE_FUNCTION(__sanitizer_sandbox_on_notify) +INTERFACE_FUNCTION(__sanitizer_set_coverage_pc_buffer) INTERFACE_FUNCTION(__sanitizer_set_death_callback) INTERFACE_FUNCTION(__sanitizer_set_report_path) INTERFACE_FUNCTION(__sanitizer_set_report_fd) Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_coverage_libcdep.cc =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_coverage_libcdep.cc +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_coverage_libcdep.cc @@ -110,7 +110,8 @@ uptr *data(); uptr size() const; - uptr *buffer() const { return pc_buffer; } + + void SetPcBuffer(uptr* data, uptr length); private: struct NamedPcRange { @@ -143,6 +144,7 @@ fd_t pc_fd; uptr *pc_buffer; + uptr pc_buffer_len; // Vector of coverage guard arrays, protected by mu. InternalMmapVectorNoCtor guard_array_vec; @@ -216,9 +218,7 @@ } pc_buffer = nullptr; - if (common_flags()->coverage_pc_buffer) - pc_buffer = reinterpret_cast(MmapNoReserveOrDie( - sizeof(uptr) * kPcArrayMaxSize, "CovInit::pc_buffer")); + pc_buffer_len = 0; cc_array = reinterpret_cast(MmapNoReserveOrDie( sizeof(uptr *) * kCcArrayMaxSize, "CovInit::cc_array")); @@ -257,10 +257,6 @@ UnmapOrDie(cc_array, sizeof(uptr *) * kCcArrayMaxSize); cc_array = nullptr; } - if (pc_buffer) { - UnmapOrDie(pc_buffer, sizeof(uptr) * kPcArrayMaxSize); - pc_buffer = nullptr; - } if (tr_event_array) { UnmapOrDie(tr_event_array, sizeof(tr_event_array[0]) * kTrEventArrayMaxSize + @@ -429,7 +425,7 @@ atomic_load(&pc_array_size, memory_order_acquire)); uptr counter = atomic_fetch_add(&coverage_counter, 1, memory_order_relaxed); pc_array[idx] = BundlePcAndCounter(pc, counter); - if (pc_buffer) pc_buffer[counter] = pc; + if (pc_buffer && counter < pc_buffer_len) pc_buffer[counter] = pc; } // Registers a pair caller=>callee. @@ -883,6 +879,11 @@ DumpCallerCalleePairs(); } +void CoverageData::SetPcBuffer(uptr* data, uptr length) { + pc_buffer = data; + pc_buffer_len = length; +} + void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args) { if (!args) return; if (!coverage_enabled) return; @@ -1018,8 +1019,12 @@ } SANITIZER_INTERFACE_ATTRIBUTE -uptr __sanitizer_get_coverage_pc_buffer(uptr **data) { - *data = coverage_data.buffer(); +void __sanitizer_set_coverage_pc_buffer(uptr *data, uptr length) { + coverage_data.SetPcBuffer(data, length); +} + +SANITIZER_INTERFACE_ATTRIBUTE +uptr __sanitizer_get_coverage_pc_buffer_pos() { return __sanitizer_get_total_unique_coverage(); } Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.inc =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.inc +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.inc @@ -144,9 +144,6 @@ COMMON_FLAG(const char *, coverage_dir, ".", "Target directory for coverage dumps. Defaults to the current " "directory.") -COMMON_FLAG(bool, coverage_pc_buffer, true, - "If set (and if 'coverage' is set too), the pcs would be collected " - "in a buffer.") COMMON_FLAG(bool, full_address_space, false, "Sanitize complete address space; " "by default kernel area on 32-bit platforms will not be sanitized") Index: compiler-rt/trunk/test/asan/TestCases/coverage-pc-buffer.cc =================================================================== --- compiler-rt/trunk/test/asan/TestCases/coverage-pc-buffer.cc +++ compiler-rt/trunk/test/asan/TestCases/coverage-pc-buffer.cc @@ -1,11 +1,13 @@ // Test __sanitizer_coverage_pc_buffer(). -// RUN: %clangxx_asan -fsanitize-coverage=edge %s -o %t && %run %t +// RUN: %clangxx_asan -fsanitize-coverage=edge -std=c++11 %s -O3 -o %t && %run %t // UNSUPPORTED: android #include +#include #include +#include #include static volatile int sink; @@ -19,47 +21,41 @@ } int main() { + uintptr_t buf_size = 1 << 20; + std::unique_ptr buf(new uintptr_t[buf_size]); + __sanitizer_set_coverage_pc_buffer(buf.get(), buf_size); + { - uintptr_t *buf = NULL; - uintptr_t sz = __sanitizer_get_coverage_pc_buffer(&buf); - assertNotZeroPcs(buf, sz); + uintptr_t sz = __sanitizer_get_coverage_pc_buffer_pos(); + assertNotZeroPcs(buf.get(), sz); assert(sz); } { - uintptr_t *buf = NULL; - uintptr_t sz = __sanitizer_get_coverage_pc_buffer(&buf); + uintptr_t sz = __sanitizer_get_coverage_pc_buffer_pos(); // call functions for the first time. foo(); bar(); - uintptr_t *buf1 = NULL; - uintptr_t sz1 = __sanitizer_get_coverage_pc_buffer(&buf1); - assertNotZeroPcs(buf1, sz1); - assert(buf1 == buf); + uintptr_t sz1 = __sanitizer_get_coverage_pc_buffer_pos(); + assertNotZeroPcs(buf.get(), sz1); assert(sz1 > sz); } { - uintptr_t *buf = NULL; - uintptr_t sz = __sanitizer_get_coverage_pc_buffer(&buf); + uintptr_t sz = __sanitizer_get_coverage_pc_buffer_pos(); // second call shouldn't increase coverage. bar(); - uintptr_t *buf1 = NULL; - uintptr_t sz1 = __sanitizer_get_coverage_pc_buffer(&buf1); - assertNotZeroPcs(buf1, sz1); - assert(buf1 == buf); + uintptr_t sz1 = __sanitizer_get_coverage_pc_buffer_pos(); assert(sz1 == sz); + assertNotZeroPcs(buf.get(), sz1); } { - uintptr_t *buf = NULL; - uintptr_t sz = __sanitizer_get_coverage_pc_buffer(&buf); + uintptr_t sz = __sanitizer_get_coverage_pc_buffer_pos(); // reset coverage to 0. __sanitizer_reset_coverage(); - uintptr_t *buf1 = NULL; - uintptr_t sz1 = __sanitizer_get_coverage_pc_buffer(&buf1); - assertNotZeroPcs(buf1, sz1); - assert(buf1 == buf); + uintptr_t sz1 = __sanitizer_get_coverage_pc_buffer_pos(); + assertNotZeroPcs(buf.get(), sz1); assert(sz1 < sz); } }