forked from OSchip/llvm-project
[DFSan] Add flag to dump the labels when the program terminates.
Differential Revision: http://reviews.llvm.org/D6306 llvm-svn: 222425
This commit is contained in:
parent
6cab6784b9
commit
101f1d82ff
|
@ -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"
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue