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 namespace memory_allocated_in_fn_call { 24 25 void sink(int *P) { 26 } // ownership-note {{Returning without deallocating memory or storing the pointer for later deallocation}} 27 28 void foo() { 29 sink(new int(5)); // expected-note {{Memory is allocated}} 30 // ownership-note@-1 {{Calling 'sink'}} 31 // ownership-note@-2 {{Returning from 'sink'}} 32 } // expected-warning {{Potential memory leak [cplusplus.NewDeleteLeaks]}} 33 // expected-note@-1 {{Potential memory leak}} 34 35 } // namespace memory_allocated_in_fn_call 36 37 namespace memory_passed_to_fn_call { 38 39 void sink(int *P) { 40 if (coin()) // ownership-note {{Assuming the condition is false}} 41 // ownership-note@-1 {{Taking false branch}} 42 delete P; 43 } // ownership-note {{Returning without deallocating memory or storing the pointer for later deallocation}} 44 45 void foo() { 46 int *ptr = new int(5); // expected-note {{Memory is allocated}} 47 sink(ptr); // ownership-note {{Calling 'sink'}} 48 // ownership-note@-1 {{Returning from 'sink'}} 49 } // expected-warning {{Potential leak of memory pointed to by 'ptr' [cplusplus.NewDeleteLeaks]}} 50 // expected-note@-1 {{Potential leak}} 51 52 } // namespace memory_passed_to_fn_call 53 54 namespace memory_shared_with_ptr_of_shorter_lifetime { 55 56 void sink(int *P) { 57 int *Q = P; 58 if (coin()) // ownership-note {{Assuming the condition is false}} 59 // ownership-note@-1 {{Taking false branch}} 60 delete P; 61 (void)Q; 62 } // ownership-note {{Returning without deallocating memory or storing the pointer for later deallocation}} 63 64 void foo() { 65 int *ptr = new int(5); // expected-note {{Memory is allocated}} 66 sink(ptr); // ownership-note {{Calling 'sink'}} 67 // ownership-note@-1 {{Returning from 'sink'}} 68 } // expected-warning {{Potential leak of memory pointed to by 'ptr' [cplusplus.NewDeleteLeaks]}} 69 // expected-note@-1 {{Potential leak}} 70 71 } // namespace memory_shared_with_ptr_of_shorter_lifetime 72 73 //===----------------------------------------------------------------------===// 74 // Report for which we *do not* expect NoOwnershipChangeVisitor add a new note, 75 // nor do we want it to. 76 //===----------------------------------------------------------------------===// 77 78 namespace memory_not_passed_to_fn_call { 79 80 void sink(int *P) { 81 if (coin()) 82 delete P; 83 } 84 85 void foo() { 86 int *ptr = new int(5); // expected-note {{Memory is allocated}} 87 int *q = nullptr; 88 sink(q); 89 (void)ptr; 90 } // expected-warning {{Potential leak of memory pointed to by 'ptr' [cplusplus.NewDeleteLeaks]}} 91 // expected-note@-1 {{Potential leak}} 92 93 } // namespace memory_not_passed_to_fn_call 94 95 namespace memory_shared_with_ptr_of_same_lifetime { 96 97 void sink(int *P, int **Q) { 98 // NOTE: Not a job of NoOwnershipChangeVisitor, but maybe this could be 99 // highlighted still? 100 *Q = P; 101 } 102 103 void foo() { 104 int *ptr = new int(5); // expected-note {{Memory is allocated}} 105 int *q = nullptr; 106 sink(ptr, &q); 107 } // expected-warning {{Potential leak of memory pointed to by 'q' [cplusplus.NewDeleteLeaks]}} 108 // expected-note@-1 {{Potential leak}} 109 110 } // namespace memory_shared_with_ptr_of_same_lifetime 111 112 // TODO: We don't want a note here. sink() doesn't seem like a function that 113 // even attempts to take care of any memory ownership problems. 114 namespace memory_passed_into_fn_that_doesnt_intend_to_free { 115 116 void sink(int *P) { 117 } // ownership-note {{Returning without deallocating memory or storing the pointer for later deallocation}} 118 119 void foo() { 120 int *ptr = new int(5); // expected-note {{Memory is allocated}} 121 sink(ptr); // ownership-note {{Calling 'sink'}} 122 // ownership-note@-1 {{Returning from 'sink'}} 123 } // expected-warning {{Potential leak of memory pointed to by 'ptr' [cplusplus.NewDeleteLeaks]}} 124 // expected-note@-1 {{Potential leak}} 125 126 } // namespace memory_passed_into_fn_that_doesnt_intend_to_free 127 128 namespace refkind_from_unoallocated_to_allocated { 129 130 // RefKind of the symbol changed from nothing to Allocated. We don't want to 131 // emit notes when the RefKind changes in the stack frame. 132 static char *malloc_wrapper_ret() { 133 return (char *)malloc(12); // expected-note {{Memory is allocated}} 134 } 135 void use_ret() { 136 char *v; 137 v = malloc_wrapper_ret(); // expected-note {{Calling 'malloc_wrapper_ret'}} 138 // expected-note@-1 {{Returned allocated memory}} 139 } // expected-warning {{Potential leak of memory pointed to by 'v' [unix.Malloc]}} 140 // expected-note@-1 {{Potential leak of memory pointed to by 'v'}} 141 142 } // namespace refkind_from_unoallocated_to_allocated 143