Skip to content

Commit

Permalink
[dfsan] Add stack-trace printing functions to dfsan interface
Browse files Browse the repository at this point in the history
Reviewed By: stephan.yichao.zhao

Differential Revision: https://reviews.llvm.org/D104165
  • Loading branch information
gbalats committed Jun 14, 2021
1 parent 585e65d commit 9850495
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 7 deletions.
17 changes: 15 additions & 2 deletions compiler-rt/include/sanitizer/dfsan_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ void dfsan_print_origin_trace(const void *addr, const char *description);
/// int len = dfsan_sprint_origin_trace(&var, nullptr, buf, sizeof(buf));
///
/// if (len < sizeof(buf)) {
/// ProcessOriginTrace(tmpbuf);
/// else {
/// ProcessOriginTrace(buf);
/// } else {
/// char *tmpbuf = new char[len + 1];
/// dfsan_sprint_origin_trace(&var, nullptr, tmpbuf, len + 1);
/// ProcessOriginTrace(tmpbuf);
Expand All @@ -125,6 +125,19 @@ void dfsan_print_origin_trace(const void *addr, const char *description);
size_t dfsan_sprint_origin_trace(const void *addr, const char *description,
char *out_buf, size_t out_buf_size);

/// Prints the stack trace leading to this call to a pre-allocated output
/// buffer.
///
/// For usage examples, see dfsan_sprint_origin_trace.
///
/// \param [out] out_buf The output buffer to write the results to.
/// \param out_buf_size The size of \p out_buf.
///
/// \returns The number of symbols that should have been written to \p out_buf
/// (not including trailing null byte '\0'). Thus, the string is truncated iff
/// return value is not less than \p out_buf_size.
size_t dfsan_sprint_stack_trace(char *out_buf, size_t out_buf_size);

/// Retrieves the very first origin associated with the data at the given
/// address.
dfsan_origin dfsan_get_init_origin(const void *addr);
Expand Down
15 changes: 10 additions & 5 deletions compiler-rt/lib/dfsan/dfsan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -824,10 +824,6 @@ dfsan_get_init_origin(const void *addr) {
return origin_id;
}

#define GET_FATAL_STACK_TRACE_PC_BP(pc, bp) \
BufferedStackTrace stack; \
stack.Unwind(pc, bp, nullptr, common_flags()->fast_unwind_on_fatal);

void __sanitizer::BufferedStackTrace::UnwindImpl(uptr pc, uptr bp,
void *context,
bool request_fast,
Expand All @@ -841,10 +837,19 @@ void __sanitizer::BufferedStackTrace::UnwindImpl(uptr pc, uptr bp,
}

extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_print_stack_trace() {
GET_FATAL_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME());
GET_CALLER_PC_BP;
GET_STORE_STACK_TRACE_PC_BP(pc, bp);
stack.Print();
}

extern "C" SANITIZER_INTERFACE_ATTRIBUTE size_t
dfsan_sprint_stack_trace(char *out_buf, size_t out_buf_size) {
CHECK(out_buf);
GET_CALLER_PC_BP;
GET_STORE_STACK_TRACE_PC_BP(pc, bp);
return stack.PrintTo(out_buf, out_buf_size);
}

void Flags::SetDefaults() {
#define DFSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
#include "dfsan_flags.inc"
Expand Down
2 changes: 2 additions & 0 deletions compiler-rt/lib/dfsan/done_abilist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ fun:dfsan_print_origin_trace=uninstrumented
fun:dfsan_print_origin_trace=discard
fun:dfsan_sprint_origin_trace=uninstrumented
fun:dfsan_sprint_origin_trace=discard
fun:dfsan_sprint_stack_trace=uninstrumented
fun:dfsan_sprint_stack_trace=discard
fun:dfsan_get_origin=uninstrumented
fun:dfsan_get_origin=custom
fun:dfsan_get_init_origin=uninstrumented
Expand Down
66 changes: 66 additions & 0 deletions compiler-rt/test/dfsan/stack_trace.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// RUN: %clang_dfsan -gmlt %s -o %t && %run %t >%t.out 2>&1
// RUN: FileCheck %s < %t.out
//
// REQUIRES: x86_64-target-arch

#include <assert.h>
#include <sanitizer/dfsan_interface.h>
#include <stdio.h>
#include <string.h>

#define NOINLINE __attribute__((noinline))

NOINLINE size_t bar(int depth, char *buf, size_t len) {
if (!depth) {
return dfsan_sprint_stack_trace(buf, len);
}

return bar(depth - 1, buf, len);
}

NOINLINE size_t baz(int depth, char *buf, size_t len) {
return bar(depth, buf, len);
}

int main(int argc, char *argv[]) {
char buf[3000];
size_t length = dfsan_sprint_stack_trace(buf, sizeof(buf));
assert(length < sizeof(buf));
printf("==OUTPUT==\n%s==EOS==\n", buf);

// CHECK: ==OUTPUT==
// CHECK: #0 {{.*}} in main [[FILEPATH:.*]]/stack_trace.c:[[# @LINE - 5 ]]
// CHECK: ==EOS==

length = baz(8, buf, sizeof(buf));
printf("==OUTPUT==\n%s==EOS==\n", buf);

// CHECK: ==OUTPUT==
// CHECK: #0 {{.*}} in dfs$bar [[FILEPATH]]/stack_trace.c:15
// CHECK-COUNT-8: #{{[1-9]+}} {{.*}} in dfs$bar [[FILEPATH]]/stack_trace.c:18
// CHECK: #9 {{.*}} in dfs$baz [[FILEPATH]]/stack_trace.c:22
// CHECK: #10 {{.*}} in main [[FILEPATH]]/stack_trace.c:[[# @LINE - 7 ]]
// CHECK: ==EOS==

char tinybuf[8];
size_t same_length = baz(8, tinybuf, sizeof(tinybuf));

printf("==TRUNCATED OUTPUT==\n%s==EOS==\n", tinybuf);
// CHECK: ==TRUNCATED OUTPUT==
// CHECK: #0 ==EOS==

printf("Returned length: %zu\n", length);
printf("Actual length: %zu\n", strlen(buf));
printf("Returned length with truncation: %zu\n", same_length);

// CHECK: Returned length: [[#LEN:]]
// CHECK: Actual length: [[#LEN]]
// CHECK: Returned length with truncation: [[#LEN]]

buf[0] = '\0';
length = baz(8, buf, 0);
printf("Output=\"%s\"\n", buf);
printf("Returned length: %zu\n", length);
// CHECK: Output=""
// CHECK: Returned length: [[#LEN]]
}

0 comments on commit 9850495

Please sign in to comment.