diff options
author | Lorenzo Martignoni <martignlo@google.com> | 2014-11-20 10:01:08 +0000 |
---|---|---|
committer | Lorenzo Martignoni <martignlo@google.com> | 2014-11-20 10:01:08 +0000 |
commit | 0e38f28170cdd253cb5e1a6049cade671a87cc84 (patch) | |
tree | 841c9ab63d3395711b79ef9f86381b5156e5c2a0 | |
parent | d62165f7c1661a7a4c13b094d82fc3325573365b (diff) |
[DFSan] Add flag to dump the labels when the program terminates.
Differential Revision: http://reviews.llvm.org/D6306
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@222425 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/sanitizer/dfsan_interface.h | 6 | ||||
-rw-r--r-- | lib/dfsan/dfsan.cc | 55 | ||||
-rw-r--r-- | lib/dfsan/dfsan.h | 2 | ||||
-rw-r--r-- | test/dfsan/dump_labels.c | 69 |
4 files changed, 130 insertions, 2 deletions
diff --git a/include/sanitizer/dfsan_interface.h b/include/sanitizer/dfsan_interface.h index bcd4ae002..79dbf2f36 100644 --- a/include/sanitizer/dfsan_interface.h +++ b/include/sanitizer/dfsan_interface.h @@ -85,6 +85,12 @@ size_t dfsan_get_label_count(void); /// callback executes. Pass in NULL to remove any callback. void dfsan_set_write_callback(dfsan_write_callback_t labeled_write_callback); +/// Writes the labels currently used by the program to the given file +/// descriptor. The lines of the output have the following format: +/// +/// <label> <parent label 1> <parent label 2> <label description if any> +void dfsan_dump_labels(int fd); + #ifdef __cplusplus } // extern "C" diff --git a/lib/dfsan/dfsan.cc b/lib/dfsan/dfsan.cc index 4150e4e49..dcc52b1bc 100644 --- a/lib/dfsan/dfsan.cc +++ b/lib/dfsan/dfsan.cc @@ -74,6 +74,14 @@ static atomic_dfsan_label *union_table(dfsan_label l1, dfsan_label l2) { return &(*(dfsan_union_table_t *) kUnionTableAddr)[l1][l2]; } +// Checks we do not run out of labels. +static void dfsan_check_label(dfsan_label label) { + if (label == kInitializingLabel) { + Report("FATAL: DataFlowSanitizer: out of labels\n"); + Die(); + } +} + // Resolves the union of two unequal labels. Nonequality is a precondition for // this function (the instrumentation pass inlines the equality test). extern "C" SANITIZER_INTERFACE_ATTRIBUTE @@ -106,7 +114,7 @@ dfsan_label __dfsan_union(dfsan_label l1, dfsan_label l2) { } else { label = atomic_fetch_add(&__dfsan_last_label, 1, memory_order_relaxed) + 1; - CHECK_NE(label, kInitializingLabel); + dfsan_check_label(label); __dfsan_label_info[label].l1 = l1; __dfsan_label_info[label].l2 = l2; } @@ -169,7 +177,7 @@ extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label dfsan_create_label(const char *desc, void *userdata) { dfsan_label label = atomic_fetch_add(&__dfsan_last_label, 1, memory_order_relaxed) + 1; - CHECK_NE(label, kInitializingLabel); + dfsan_check_label(label); __dfsan_label_info[label].l1 = __dfsan_label_info[label].l2 = 0; __dfsan_label_info[label].desc = desc; __dfsan_label_info[label].userdata = userdata; @@ -259,14 +267,50 @@ dfsan_get_label_count(void) { return static_cast<uptr>(max_label_allocated); } +extern "C" SANITIZER_INTERFACE_ATTRIBUTE void +dfsan_dump_labels(int fd) { + dfsan_label last_label = + atomic_load(&__dfsan_last_label, memory_order_relaxed); + + for (uptr l = 1; l <= last_label; ++l) { + char buf[64]; + internal_snprintf(buf, sizeof(buf), "%u %u %u ", l, + __dfsan_label_info[l].l1, __dfsan_label_info[l].l2); + internal_write(fd, buf, internal_strlen(buf)); + if (__dfsan_label_info[l].l1 == 0 && __dfsan_label_info[l].desc) { + internal_write(fd, __dfsan_label_info[l].desc, + internal_strlen(__dfsan_label_info[l].desc)); + } + internal_write(fd, "\n", 1); + } +} + static void InitializeFlags(Flags &f, const char *env) { f.warn_unimplemented = true; f.warn_nonzero_labels = false; f.strict_data_dependencies = true; + f.dump_labels_at_exit = ""; ParseFlag(env, &f.warn_unimplemented, "warn_unimplemented", ""); ParseFlag(env, &f.warn_nonzero_labels, "warn_nonzero_labels", ""); ParseFlag(env, &f.strict_data_dependencies, "strict_data_dependencies", ""); + ParseFlag(env, &f.dump_labels_at_exit, "dump_labels_at_exit", ""); +} + +static void dfsan_fini() { + if (internal_strcmp(flags().dump_labels_at_exit, "") != 0) { + fd_t fd = OpenFile(flags().dump_labels_at_exit, true /* write */); + if (fd == kInvalidFd) { + Report("WARNING: DataFlowSanitizer: unable to open output file %s\n", + flags().dump_labels_at_exit); + return; + } + + Report("INFO: DataFlowSanitizer: dumping labels to %s\n", + flags().dump_labels_at_exit); + dfsan_dump_labels(fd); + internal_close(fd); + } } #ifdef DFSAN_NOLIBC @@ -288,6 +332,13 @@ static void dfsan_init(int argc, char **argv, char **envp) { InitializeFlags(flags(), GetEnv("DFSAN_OPTIONS")); InitializeInterceptors(); + + // Register the fini callback to run when the program terminates successfully + // or it is killed by the runtime. + Atexit(dfsan_fini); + SetDieCallback(dfsan_fini); + + __dfsan_label_info[kInitializingLabel].desc = "<init label>"; } #if !defined(DFSAN_NOLIBC) && SANITIZER_CAN_USE_PREINIT_ARRAY diff --git a/lib/dfsan/dfsan.h b/lib/dfsan/dfsan.h index ffa98d878..1b6c15091 100644 --- a/lib/dfsan/dfsan.h +++ b/lib/dfsan/dfsan.h @@ -61,6 +61,8 @@ struct Flags { // comparison might be data-dependent on the content of the strings). This // applies only to the custom functions defined in 'custom.c'. bool strict_data_dependencies; + // The path of the file where to dump the labels when the program terminates. + const char* dump_labels_at_exit; }; extern Flags flags_data; diff --git a/test/dfsan/dump_labels.c b/test/dfsan/dump_labels.c new file mode 100644 index 000000000..67801af18 --- /dev/null +++ b/test/dfsan/dump_labels.c @@ -0,0 +1,69 @@ +// RUN: %clang_dfsan -m64 %s -o %t +// RUN: DFSAN_OPTIONS=dump_labels_at_exit=/dev/stdout %run %t 2>&1 | FileCheck %s +// RUN: DFSAN_OPTIONS=dump_labels_at_exit=/dev/stdout not %run %t c 2>&1 | FileCheck %s --check-prefix=CHECK-OOL +// RUN: DFSAN_OPTIONS=dump_labels_at_exit=/dev/stdout not %run %t u 2>&1 | FileCheck %s --check-prefix=CHECK-OOL + +// Tests that labels are properly dumped at program termination. + +#include <sanitizer/dfsan_interface.h> +#include <assert.h> +#include <stdio.h> + +int main(int argc, char** argv) { + int i = 1; + dfsan_label i_label = dfsan_create_label("i", 0); + dfsan_set_label(i_label, &i, sizeof(i)); + + int j = 2; + dfsan_label j_label = dfsan_create_label("j", 0); + dfsan_set_label(j_label, &j, sizeof(j)); + + int k = 3; + dfsan_label k_label = dfsan_create_label("k", 0); + dfsan_set_label(k_label, &k, sizeof(k)); + + dfsan_label ij_label = dfsan_get_label(i + j); + dfsan_label ijk_label = dfsan_get_label(i + j + k); + + fprintf(stderr, "i %d j %d k %d ij %d ijk %d\n", i_label, j_label, k_label, + ij_label, ijk_label); + + // CHECK: 1 0 0 i + // CHECK: 2 0 0 j + // CHECK: 3 0 0 k + // CHECK: 4 1 2 + // CHECK: 5 3 4 + + if (argc > 1) { + // Exhaust the labels. + unsigned long num_labels = 1 << (sizeof(dfsan_label) * 8); + for (unsigned long i = ijk_label + 1; i < num_labels - 2; ++i) { + dfsan_label l = dfsan_create_label("l", 0); + assert(l == i); + } + + // Consume the last available label. + dfsan_label l = dfsan_union(5, 6); + assert(l == num_labels - 2); + + // Try to allocate another label (either explicitly or by unioning two + // existing labels), but expect a crash. + if (argv[1][0] == 'c') { + l = dfsan_create_label("l", 0); + } else { + l = dfsan_union(6, 7); + } + + // CHECK-OOL: FATAL: DataFlowSanitizer: out of labels + // CHECK-OOL: 1 0 0 i + // CHECK-OOL: 2 0 0 j + // CHECK-OOL: 3 0 0 k + // CHECK-OOL: 4 1 2 + // CHECK-OOL: 5 3 4 + // CHECK-OOL: 6 0 0 + // CHECK-OOL: 65534 5 6 + // CHECK-OOL: 65535 0 0 <init label> + } + + return 0; +} |