1 | // RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config max-nodes=12 -verify %s |
2 | |
3 | // Here we test how "suppress on sink" feature of certain bugtypes interacts |
4 | // with reaching analysis limits. |
5 | |
6 | // If we report a warning of a bug-type with "suppress on sink" attribute set |
7 | // (such as MallocChecker's memory leak warning), then failing to reach the |
8 | // reason for the sink (eg. no-return function such as "exit()") due to analysis |
9 | // limits (eg. max-nodes option), we may produce a false positive. |
10 | |
11 | typedef __typeof(sizeof(int)) size_t; |
12 | void *malloc(size_t); |
13 | |
14 | extern void exit(int) __attribute__ ((__noreturn__)); |
15 | |
16 | void clang_analyzer_warnIfReached(void); |
17 | |
18 | int coin(); |
19 | |
20 | void test_single_cfg_block_sink() { |
21 | void *p = malloc(1); // no-warning (wherever the leak warning may occur here) |
22 | |
23 | // Due to max-nodes option in the run line, we should reach the first call |
24 | // but bail out before the second call. |
25 | // If the test on these two lines starts failing, see if modifying |
26 | // the max-nodes run-line helps. |
27 | clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} |
28 | clang_analyzer_warnIfReached(); // no-warning |
29 | |
30 | // Even though we do not reach this line, we should still suppress |
31 | // the leak report. |
32 | exit(0); |
33 | } |
34 | |
35 | // A similar test with more complicated control flow before the no-return thing, |
36 | // so that the no-return thing wasn't in the same CFG block. |
37 | void test_more_complex_control_flow_before_sink() { |
38 | void *p = malloc(1); // no-warning |
39 | |
40 | clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} |
41 | clang_analyzer_warnIfReached(); // no-warning |
42 | |
43 | if (coin()) |
44 | exit(0); |
45 | else |
46 | exit(1); |
47 | } |
48 | |
49 | // A loop before the no-return function, to make sure that |
50 | // the dominated-by-sink analysis doesn't hang. |
51 | void test_loop_before_sink(int n) { |
52 | void *p = malloc(1); // no-warning |
53 | |
54 | clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} |
55 | clang_analyzer_warnIfReached(); // no-warning |
56 | |
57 | for (int i = 0; i < n; ++i) { |
58 | } |
59 | exit(1); |
60 | } |
61 | |
62 | // We're not sure if this is no-return. |
63 | void test_loop_with_sink(int n) { |
64 | void *p = malloc(1); // expected-warning@+2{{Potential leak of memory}} |
65 | |
66 | clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} |
67 | clang_analyzer_warnIfReached(); // no-warning |
68 | |
69 | for (int i = 0; i < n; ++i) |
70 | if (i == 0) |
71 | exit(1); |
72 | } |
73 | |
74 | // Handle unreachable blocks correctly. |
75 | void test_unreachable_successor_blocks() { |
76 | void *p = malloc(1); // no-warning |
77 | |
78 | clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} |
79 | clang_analyzer_warnIfReached(); // no-warning |
80 | |
81 | if (1) // no-crash |
82 | exit(1); |
83 | } |
84 | |