1 // RUN: %clang_analyze_cc1 -verify -analyzer-output=text %s \ 2 // RUN: -analyzer-checker=core \ 3 // RUN: -analyzer-checker=cplusplus \ 4 // RUN: -analyzer-checker=unix \ 5 // RUN: -analyzer-config \ 6 // RUN: unix.DynamicMemoryModeling:AddNoOwnershipChangeNotes=false 7 8 // RUN: %clang_analyze_cc1 -verify=expected,ownership -analyzer-output=text %s \ 9 // RUN: -analyzer-checker=core \ 10 // RUN: -analyzer-checker=cplusplus \ 11 // RUN: -analyzer-checker=unix \ 12 // RUN: -analyzer-config \ 13 // RUN: unix.DynamicMemoryModeling:AddNoOwnershipChangeNotes=true 14 15 #include "Inputs/system-header-simulator-for-malloc.h" 16 17 //===----------------------------------------------------------------------===// 18 // Report for which we expect NoOwnershipChangeVisitor to add a new note. 19 //===----------------------------------------------------------------------===// 20 21 bool coin(); 22 23 // TODO: AST analysis of sink would reveal that it doesn't intent to free the 24 // allocated memory, but in this instance, its also the only function with 25 // the ability to do so, we should see a note here. 26 namespace memory_allocated_in_fn_call { 27 28 void sink(int *P) { 29 } 30 31 void foo() { 32 sink(new int(5)); // expected-note {{Memory is allocated}} 33 } // expected-warning {{Potential memory leak [cplusplus.NewDeleteLeaks]}} 34 // expected-note@-1 {{Potential memory leak}} 35 36 } // namespace memory_allocated_in_fn_call 37 38 namespace memory_passed_to_fn_call { 39 40 void sink(int *P) { 41 if (coin()) // ownership-note {{Assuming the condition is false}} 42 // ownership-note@-1 {{Taking false branch}} 43 delete P; 44 } // ownership-note {{Returning without deallocating memory or storing the pointer for later deallocation}} 45 46 void foo() { 47 int *ptr = new int(5); // expected-note {{Memory is allocated}} 48 sink(ptr); // ownership-note {{Calling 'sink'}} 49 // ownership-note@-1 {{Returning from 'sink'}} 50 } // expected-warning {{Potential leak of memory pointed to by 'ptr' [cplusplus.NewDeleteLeaks]}} 51 // expected-note@-1 {{Potential leak}} 52 53 } // namespace memory_passed_to_fn_call 54 55 namespace memory_shared_with_ptr_of_shorter_lifetime { 56 57 void sink(int *P) { 58 int *Q = P; 59 if (coin()) // ownership-note {{Assuming the condition is false}} 60 // ownership-note@-1 {{Taking false branch}} 61 delete P; 62 (void)Q; 63 } // ownership-note {{Returning without deallocating memory or storing the pointer for later deallocation}} 64 65 void foo() { 66 int *ptr = new int(5); // expected-note {{Memory is allocated}} 67 sink(ptr); // ownership-note {{Calling 'sink'}} 68 // ownership-note@-1 {{Returning from 'sink'}} 69 } // expected-warning {{Potential leak of memory pointed to by 'ptr' [cplusplus.NewDeleteLeaks]}} 70 // expected-note@-1 {{Potential leak}} 71 72 } // namespace memory_shared_with_ptr_of_shorter_lifetime 73 74 //===----------------------------------------------------------------------===// 75 // Report for which we *do not* expect NoOwnershipChangeVisitor add a new note, 76 // nor do we want it to. 77 //===----------------------------------------------------------------------===// 78 79 namespace memory_not_passed_to_fn_call { 80 81 void sink(int *P) { 82 if (coin()) 83 delete P; 84 } 85 86 void foo() { 87 int *ptr = new int(5); // expected-note {{Memory is allocated}} 88 int *q = nullptr; 89 sink(q); 90 (void)ptr; 91 } // expected-warning {{Potential leak of memory pointed to by 'ptr' [cplusplus.NewDeleteLeaks]}} 92 // expected-note@-1 {{Potential leak}} 93 94 } // namespace memory_not_passed_to_fn_call 95 96 namespace memory_shared_with_ptr_of_same_lifetime { 97 98 void sink(int *P, int **Q) { 99 // NOTE: Not a job of NoOwnershipChangeVisitor, but maybe this could be 100 // highlighted still? 101 *Q = P; 102 } 103 104 void foo() { 105 int *ptr = new int(5); // expected-note {{Memory is allocated}} 106 int *q = nullptr; 107 sink(ptr, &q); 108 } // expected-warning {{Potential leak of memory pointed to by 'q' [cplusplus.NewDeleteLeaks]}} 109 // expected-note@-1 {{Potential leak}} 110 111 } // namespace memory_shared_with_ptr_of_same_lifetime 112 113 namespace memory_passed_into_fn_that_doesnt_intend_to_free { 114 115 void sink(int *P) { 116 } 117 118 void foo() { 119 int *ptr = new int(5); // expected-note {{Memory is allocated}} 120 sink(ptr); 121 } // expected-warning {{Potential leak of memory pointed to by 'ptr' [cplusplus.NewDeleteLeaks]}} 122 // expected-note@-1 {{Potential leak}} 123 124 } // namespace memory_passed_into_fn_that_doesnt_intend_to_free 125 126 namespace refkind_from_unoallocated_to_allocated { 127 128 // RefKind of the symbol changed from nothing to Allocated. We don't want to 129 // emit notes when the RefKind changes in the stack frame. 130 static char *malloc_wrapper_ret() { 131 return (char *)malloc(12); // expected-note {{Memory is allocated}} 132 } 133 void use_ret() { 134 char *v; 135 v = malloc_wrapper_ret(); // expected-note {{Calling 'malloc_wrapper_ret'}} 136 // expected-note@-1 {{Returned allocated memory}} 137 } // expected-warning {{Potential leak of memory pointed to by 'v' [unix.Malloc]}} 138 // expected-note@-1 {{Potential leak of memory pointed to by 'v'}} 139 140 } // namespace refkind_from_unoallocated_to_allocated 141