| 1 | // RUN: %clang_analyze_cc1 -x c -analyzer-checker=core -analyzer-output=text -verify %s |
| 2 | |
| 3 | #define NULL 0 |
| 4 | |
| 5 | int test_noparammacro() { |
| 6 | int *x = NULL; // expected-note{{'x' initialized to a null pointer value}} |
| 7 | return *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}} |
| 8 | // expected-note@-1{{Dereference of null pointer (loaded from variable 'x')}} |
| 9 | } |
| 10 | |
| 11 | #define DYN_CAST(X) (X ? (char*)X : 0) |
| 12 | #define GENERATE_NUMBER(X) (0) |
| 13 | |
| 14 | char test_assignment(int *param) { |
| 15 | char *param2; |
| 16 | param2 = DYN_CAST(param); |
| 17 | return *param2; |
| 18 | } |
| 19 | |
| 20 | char test_declaration(int *param) { |
| 21 | char *param2 = DYN_CAST(param); |
| 22 | return *param2; |
| 23 | } |
| 24 | |
| 25 | int coin(); |
| 26 | |
| 27 | int test_multi_decl(int *paramA, int *paramB) { |
| 28 | char *param1 = DYN_CAST(paramA), *param2 = DYN_CAST(paramB); |
| 29 | if (coin()) |
| 30 | return *param1; |
| 31 | return *param2; |
| 32 | } |
| 33 | |
| 34 | int testDivision(int a) { |
| 35 | int divider = GENERATE_NUMBER(2); // expected-note{{'divider' initialized to 0}} |
| 36 | return 1/divider; // expected-warning{{Division by zero}} |
| 37 | // expected-note@-1{{Division by zero}} |
| 38 | } |
| 39 | |
| 40 | // Warning should not be suppressed if it happens in the same macro. |
| 41 | #define DEREF_IN_MACRO(X) int fn() {int *p = 0; return *p; } |
| 42 | |
| 43 | DEREF_IN_MACRO(0) // expected-warning{{Dereference of null pointer}} |
| 44 | // expected-note@-1{{'p' initialized to a null}} |
| 45 | // expected-note@-2{{Dereference of null pointer}} |
| 46 | |
| 47 | // Warning should not be suppressed if the null returned by the macro |
| 48 | // is not related to the warning. |
| 49 | #define RETURN_NULL() (0) |
| 50 | extern int* returnFreshPointer(); |
| 51 | int noSuppressMacroUnrelated() { |
| 52 | int *x = RETURN_NULL(); |
| 53 | x = returnFreshPointer(); // expected-note{{Value assigned to 'x'}} |
| 54 | if (x) {} // expected-note{{Taking false branch}} |
| 55 | // expected-note@-1{{Assuming 'x' is null}} |
| 56 | return *x; // expected-warning{{Dereference of null pointer}} |
| 57 | // expected-note@-1{{Dereference}} |
| 58 | } |
| 59 | |
| 60 | // Value haven't changed by the assignment, but the null pointer |
| 61 | // did not come from the macro. |
| 62 | int noSuppressMacroUnrelatedOtherReason() { |
| 63 | int *x = RETURN_NULL(); |
| 64 | x = returnFreshPointer(); |
| 65 | x = 0; // expected-note{{Null pointer value stored to 'x'}} |
| 66 | return *x; // expected-warning{{Dereference of null pointer}} |
| 67 | // expected-note@-1{{Dereference}} |
| 68 | } |
| 69 | |