Index: include/sanitizer/dfsan_interface.h =================================================================== --- include/sanitizer/dfsan_interface.h +++ include/sanitizer/dfsan_interface.h @@ -85,6 +85,12 @@ /// 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" Index: lib/dfsan/dfsan.h =================================================================== --- lib/dfsan/dfsan.h +++ lib/dfsan/dfsan.h @@ -61,6 +61,8 @@ // 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; Index: lib/dfsan/dfsan.cc =================================================================== --- lib/dfsan/dfsan.cc +++ lib/dfsan/dfsan.cc @@ -70,10 +70,21 @@ static const uptr kUnusedAddr = kUnionTableAddr + sizeof(dfsan_union_table_t); static const uptr kAppAddr = 0x700000008000; +static void dfsan_fini(); + 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"); + dfsan_fini(); + 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 +117,7 @@ } 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 +180,7 @@ 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 +270,33 @@ 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 (dfsan_label l = 0; 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", ""); } #ifdef DFSAN_NOLIBC @@ -290,7 +320,25 @@ InitializeInterceptors(); } +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); + } +} + #if !defined(DFSAN_NOLIBC) && SANITIZER_CAN_USE_PREINIT_ARRAY __attribute__((section(".preinit_array"), used)) static void (*dfsan_init_ptr)(int, char **, char **) = dfsan_init; +__attribute__((section(".fini_array"), used)) +static void (*dfsan_fini_ptr)() = dfsan_fini; #endif