1 // RUN: %clang_dfsan -gmlt %s -o %t && %run %t >%t.out 2>&1
2 // RUN: FileCheck %s < %t.out
3 //
4 // REQUIRES: x86_64-target-arch
5 
6 #include <assert.h>
7 #include <sanitizer/dfsan_interface.h>
8 #include <stdio.h>
9 #include <string.h>
10 
11 #define NOINLINE __attribute__((noinline))
12 
bar(int depth,char * buf,size_t len)13 NOINLINE size_t bar(int depth, char *buf, size_t len) {
14   if (!depth) {
15     return dfsan_sprint_stack_trace(buf, len);
16   }
17 
18   return bar(depth - 1, buf, len);
19 }
20 
baz(int depth,char * buf,size_t len)21 NOINLINE size_t baz(int depth, char *buf, size_t len) {
22   return bar(depth, buf, len);
23 }
24 
main(int argc,char * argv[])25 int main(int argc, char *argv[]) {
26   char buf[3000];
27   size_t length = dfsan_sprint_stack_trace(buf, sizeof(buf));
28   assert(length < sizeof(buf));
29   printf("==OUTPUT==\n%s==EOS==\n", buf);
30 
31   // CHECK: ==OUTPUT==
32   // CHECK: #0 {{.*}} in main [[FILEPATH:.*]]/stack_trace.c:[[# @LINE - 5 ]]
33   // CHECK: ==EOS==
34 
35   length = baz(8, buf, sizeof(buf));
36   printf("==OUTPUT==\n%s==EOS==\n", buf);
37 
38   // CHECK: ==OUTPUT==
39   // CHECK: #0 {{.*}} in bar.dfsan [[FILEPATH]]/stack_trace.c:15
40   // CHECK-COUNT-8: #{{[1-9]+}} {{.*}} in bar.dfsan [[FILEPATH]]/stack_trace.c:18
41   // CHECK: #9 {{.*}} in baz.dfsan [[FILEPATH]]/stack_trace.c:22
42   // CHECK: #10 {{.*}} in main [[FILEPATH]]/stack_trace.c:[[# @LINE - 7 ]]
43   // CHECK: ==EOS==
44 
45   char tinybuf[8];
46   size_t same_length = baz(8, tinybuf, sizeof(tinybuf));
47 
48   printf("==TRUNCATED OUTPUT==\n%s==EOS==\n", tinybuf);
49   // CHECK: ==TRUNCATED OUTPUT==
50   // CHECK:     #0 ==EOS==
51 
52   printf("Returned length: %zu\n", length);
53   printf("Actual length: %zu\n", strlen(buf));
54   printf("Returned length with truncation: %zu\n", same_length);
55 
56   // CHECK: Returned length: [[#LEN:]]
57   // CHECK: Actual length: [[#LEN]]
58   // CHECK: Returned length with truncation: [[#LEN]]
59 
60   buf[0] = '\0';
61   length = baz(8, buf, 0);
62   printf("Output=\"%s\"\n", buf);
63   printf("Returned length: %zu\n", length);
64   // CHECK: Output=""
65   // CHECK: Returned length: [[#LEN]]
66 }
67