summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarco Castelluccio <mcastelluccio@mozilla.com>2018-01-03 11:21:30 +0000
committerMarco Castelluccio <mcastelluccio@mozilla.com>2018-01-03 11:21:30 +0000
commit860d7953a6f36980f406bfbff76f3c00f15eed57 (patch)
tree27d983193730bc6b98544e847b336a737eb26965
parent767c0196489b75a48554c7429d7a3b68ab0180c3 (diff)
Hide some symbols to avoid a crash on shutdown when using code coverage
Summary: gcov / gcda-based profiling crashes when shared libraries are unloaded Patch by Benoit Belley and test by Marco Castelluccio for Firefox See https://bugs.llvm.org/show_bug.cgi?id=27224 & https://bugzilla.mozilla.org/show_bug.cgi?id=1401230 Reviewers: davidxl, rnk, void Subscribers: jessicah, marco-c, belleyb, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D38124 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@321703 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/profile/GCDAProfiling.c13
-rw-r--r--test/profile/Inputs/instrprof-dlopen-dlclose-main.c26
-rw-r--r--test/profile/instrprof-dlopen-dlclose-gcov.test6
3 files changed, 45 insertions, 0 deletions
diff --git a/lib/profile/GCDAProfiling.c b/lib/profile/GCDAProfiling.c
index 4908c246a..bb70ff0cf 100644
--- a/lib/profile/GCDAProfiling.c
+++ b/lib/profile/GCDAProfiling.c
@@ -228,6 +228,7 @@ static void unmap_file() {
* profiling enabled will emit to a different file. Only one file may be
* started at a time.
*/
+COMPILER_RT_VISIBILITY
void llvm_gcda_start_file(const char *orig_filename, const char version[4],
uint32_t checksum) {
const char *mode = "r+b";
@@ -295,6 +296,7 @@ void llvm_gcda_start_file(const char *orig_filename, const char version[4],
/* Given an array of pointers to counters (counters), increment the n-th one,
* where we're also given a pointer to n (predecessor).
*/
+COMPILER_RT_VISIBILITY
void llvm_gcda_increment_indirect_counter(uint32_t *predecessor,
uint64_t **counters) {
uint64_t *counter;
@@ -317,6 +319,7 @@ void llvm_gcda_increment_indirect_counter(uint32_t *predecessor,
#endif
}
+COMPILER_RT_VISIBILITY
void llvm_gcda_emit_function(uint32_t ident, const char *function_name,
uint32_t func_checksum, uint8_t use_extra_checksum,
uint32_t cfg_checksum) {
@@ -343,6 +346,7 @@ void llvm_gcda_emit_function(uint32_t ident, const char *function_name,
write_string(function_name);
}
+COMPILER_RT_VISIBILITY
void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) {
uint32_t i;
uint64_t *old_ctrs = NULL;
@@ -394,6 +398,7 @@ void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) {
#endif
}
+COMPILER_RT_VISIBILITY
void llvm_gcda_summary_info() {
const uint32_t obj_summary_len = 9; /* Length for gcov compatibility. */
uint32_t i;
@@ -447,6 +452,7 @@ void llvm_gcda_summary_info() {
#endif
}
+COMPILER_RT_VISIBILITY
void llvm_gcda_end_file() {
/* Write out EOF record. */
if (output_file) {
@@ -472,6 +478,7 @@ void llvm_gcda_end_file() {
#endif
}
+COMPILER_RT_VISIBILITY
void llvm_register_writeout_function(writeout_fn fn) {
struct writeout_fn_node *new_node = malloc(sizeof(struct writeout_fn_node));
new_node->fn = fn;
@@ -485,6 +492,7 @@ void llvm_register_writeout_function(writeout_fn fn) {
}
}
+COMPILER_RT_VISIBILITY
void llvm_writeout_files(void) {
struct writeout_fn_node *curr = writeout_fn_head;
@@ -494,6 +502,7 @@ void llvm_writeout_files(void) {
}
}
+COMPILER_RT_VISIBILITY
void llvm_delete_writeout_function_list(void) {
while (writeout_fn_head) {
struct writeout_fn_node *node = writeout_fn_head;
@@ -504,6 +513,7 @@ void llvm_delete_writeout_function_list(void) {
writeout_fn_head = writeout_fn_tail = NULL;
}
+COMPILER_RT_VISIBILITY
void llvm_register_flush_function(flush_fn fn) {
struct flush_fn_node *new_node = malloc(sizeof(struct flush_fn_node));
new_node->fn = fn;
@@ -517,6 +527,7 @@ void llvm_register_flush_function(flush_fn fn) {
}
}
+COMPILER_RT_VISIBILITY
void __gcov_flush() {
struct flush_fn_node *curr = flush_fn_head;
@@ -526,6 +537,7 @@ void __gcov_flush() {
}
}
+COMPILER_RT_VISIBILITY
void llvm_delete_flush_function_list(void) {
while (flush_fn_head) {
struct flush_fn_node *node = flush_fn_head;
@@ -536,6 +548,7 @@ void llvm_delete_flush_function_list(void) {
flush_fn_head = flush_fn_tail = NULL;
}
+COMPILER_RT_VISIBILITY
void llvm_gcov_init(writeout_fn wfn, flush_fn ffn) {
static int atexit_ran = 0;
diff --git a/test/profile/Inputs/instrprof-dlopen-dlclose-main.c b/test/profile/Inputs/instrprof-dlopen-dlclose-main.c
new file mode 100644
index 000000000..fe7eaf0b5
--- /dev/null
+++ b/test/profile/Inputs/instrprof-dlopen-dlclose-main.c
@@ -0,0 +1,26 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char *argv[]) {
+ dlerror();
+ void *f1_handle = dlopen("func.shared", RTLD_LAZY | RTLD_GLOBAL);
+ if (f1_handle == NULL) {
+ fprintf(stderr, "unable to open 'func.shared': %s\n", dlerror());
+ return EXIT_FAILURE;
+ }
+
+ void *f2_handle = dlopen("func2.shared", RTLD_LAZY | RTLD_GLOBAL);
+ if (f2_handle == NULL) {
+ fprintf(stderr, "unable to open 'func2.shared': %s\n", dlerror());
+ return EXIT_FAILURE;
+ }
+
+ if (dlclose(f2_handle) != 0) {
+ fprintf(stderr, "unable to close 'func2.shared': %s\n", dlerror());
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
diff --git a/test/profile/instrprof-dlopen-dlclose-gcov.test b/test/profile/instrprof-dlopen-dlclose-gcov.test
new file mode 100644
index 000000000..a785fe32d
--- /dev/null
+++ b/test/profile/instrprof-dlopen-dlclose-gcov.test
@@ -0,0 +1,6 @@
+RUN: mkdir -p %t.d
+RUN: %clang --coverage -o %t.d/func.shared -fPIC -shared %S/Inputs/instrprof-dlopen-func.c
+RUN: %clang --coverage -o %t.d/func2.shared -fPIC -shared %S/Inputs/instrprof-dlopen-func2.c
+RUN: %clang --coverage -o %t -fPIC -rpath %t.d %S/Inputs/instrprof-dlopen-dlclose-main.c
+
+RUN: %run %t