1 | // RUN: %clang_dfsan -fno-sanitize=dataflow -O2 -fPIE -DCALLBACKS -c %s -o %t-callbacks.o |
2 | // RUN: %clang_dfsan -fsanitize-ignorelist=%S/Inputs/flags_abilist.txt -O2 -mllvm -dfsan-conditional-callbacks %s %t-callbacks.o -o %t |
3 | // RUN: %run %t FooBarBaz 2>&1 | FileCheck %s |
4 | |
5 | #include <assert.h> |
6 | #include <sanitizer/dfsan_interface.h> |
7 | #include <signal.h> |
8 | #include <stdio.h> |
9 | #include <string.h> |
10 | #include <sys/types.h> |
11 | #include <unistd.h> |
12 | |
13 | #ifdef CALLBACKS |
14 | // Compile this code without DFSan to avoid recursive instrumentation. |
15 | |
16 | void my_dfsan_conditional_callback(dfsan_label Label, dfsan_origin Origin) { |
17 | assert(Label != 0); |
18 | assert(Origin == 0); |
19 | |
20 | static int Count = 0; |
21 | switch (Count++) { |
22 | case 0: |
23 | assert(Label == 1); |
24 | break; |
25 | case 1: |
26 | assert(Label == 4); |
27 | break; |
28 | default: |
29 | break; |
30 | } |
31 | |
32 | fprintf(stderr, "Label %u used as condition\n" , Label); |
33 | } |
34 | |
35 | #else |
36 | // Compile this code with DFSan and -dfsan-conditional-callbacks to insert the |
37 | // callbacks. |
38 | |
39 | extern void my_dfsan_conditional_callback(dfsan_label Label, |
40 | dfsan_origin Origin); |
41 | |
42 | volatile int x = 0; |
43 | volatile int y = 1; |
44 | volatile int z = 0; |
45 | |
46 | void SignalHandler(int signo) { |
47 | assert(dfsan_get_label(x) == 0); |
48 | assert(dfsan_get_label(y) != 0); |
49 | assert(dfsan_get_label(z) != 0); |
50 | // Running the conditional callback from a signal handler is risky, |
51 | // because the code must be written with signal handler context in mind. |
52 | // Instead dfsan_get_labels_in_signal_conditional() will indicate labels |
53 | // used in conditions inside signal handlers. |
54 | // CHECK-NOT: Label 8 used as condition |
55 | if (z != 0) { |
56 | x = y; |
57 | } |
58 | } |
59 | |
60 | int main(int Argc, char *Argv[]) { |
61 | assert(Argc >= 1); |
62 | int unknown = (Argv[0][0] != 0) ? 1 : 0; |
63 | dfsan_set_label(label: 1, addr: &unknown, size: sizeof(unknown)); |
64 | |
65 | dfsan_set_conditional_callback(callback: my_dfsan_conditional_callback); |
66 | |
67 | // CHECK: Label 1 used as condition |
68 | if (unknown) { |
69 | z = 42; |
70 | } |
71 | |
72 | assert(dfsan_get_labels_in_signal_conditional() == 0); |
73 | dfsan_set_label(label: 4, addr: (void *)&y, size: sizeof(y)); |
74 | dfsan_set_label(label: 8, addr: (void *)&z, size: sizeof(z)); |
75 | |
76 | struct sigaction sa = {}; |
77 | sa.sa_handler = SignalHandler; |
78 | int r = sigaction(SIGHUP, act: &sa, NULL); |
79 | assert(dfsan_get_label(r) == 0); |
80 | |
81 | kill(pid: getpid(), SIGHUP); |
82 | signal(SIGHUP, SIG_DFL); |
83 | |
84 | assert(dfsan_get_labels_in_signal_conditional() == 8); |
85 | assert(x == 1); |
86 | // CHECK: Label 4 used as condition |
87 | if (x != 0) { |
88 | z = 123; |
89 | } |
90 | // Flush should clear the conditional signals seen. |
91 | dfsan_flush(); |
92 | assert(dfsan_get_labels_in_signal_conditional() == 0); |
93 | return 0; |
94 | } |
95 | |
96 | #endif // #ifdef CALLBACKS |
97 | |