| 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 | |