[gcov] Move llvm_writeout_files from atexit to a static destructor

atexit registered functions run earlier so `__attribute__((destructor))`
annotated functions cannot be tracked.

Set a priority of 100 (compatible with GCC 7 onwards) to track
destructors and destructors whose priorities are greater than 100.

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=7970

Reviewed By: calixte, marco-c

Differential Revision: https://reviews.llvm.org/D82253
This commit is contained in:
Fangrui Song
2020-07-01 16:40:31 -07:00
parent 6f13299c02
commit 48c196f5c8
2 changed files with 44 additions and 4 deletions

View File

@@ -628,8 +628,14 @@ void llvm_writeout_files(void) {
}
}
COMPILER_RT_VISIBILITY
void llvm_delete_writeout_function_list(void) {
#ifndef _WIN32
// __attribute__((destructor)) and destructors whose priorities are greater than
// 100 run before this function and can thus be tracked. The priority is
// compatible with GCC 7 onwards.
__attribute__((destructor(100)))
#endif
static void llvm_writeout_and_clear(void) {
llvm_writeout_files();
fn_list_remove(&writeout_fn_list);
}
@@ -710,8 +716,9 @@ void llvm_gcov_init(fn_ptr wfn, fn_ptr ffn, fn_ptr rfn) {
/* Make sure we write out the data and delete the data structures. */
atexit(llvm_delete_reset_function_list);
atexit(llvm_delete_flush_function_list);
atexit(llvm_delete_writeout_function_list);
atexit(llvm_writeout_files);
#ifdef _WIN32
atexit(llvm_writeout_and_clear);
#endif
}
}

View File

@@ -0,0 +1,33 @@
/// Test that destructors and destructors whose priorities are greater than 100 are tracked.
// RUN: mkdir -p %t.dir && cd %t.dir
// RUN: %clang --coverage %s -o %t
// RUN: rm -f gcov-destructor.gcda && %run %t
// RUN: llvm-cov gcov -t gcov-destructor.gcda | FileCheck %s
#include <unistd.h>
void before_exec() {} // CHECK: 1: [[#@LINE]]:void before_exec
void after_exec() {} // CHECK-NEXT: 1: [[#@LINE]]:void after_exec
__attribute__((constructor)) // CHECK: -: [[#@LINE]]:__attribute__
void constructor() {} // CHECK-NEXT: 1: [[#@LINE]]:
/// Runs before __llvm_gcov_writeout.
__attribute__((destructor)) // CHECK: -: [[#@LINE]]:__attribute__
void destructor() {} // CHECK-NEXT: 1: [[#@LINE]]:
__attribute__((destructor(101))) // CHECK: -: [[#@LINE]]:__attribute__
void destructor_101() {} // CHECK-NEXT: 1: [[#@LINE]]:
/// Runs after __llvm_gcov_writeout.
__attribute__((destructor(99))) // CHECK: -: [[#@LINE]]:__attribute__
void destructor_99() {} // CHECK-NEXT: #####: [[#@LINE]]:
int main() {
before_exec();
// Implicit writeout.
execl("/not_exist", "not_exist", (char *)0);
// Still tracked.
after_exec();
return 0;
}