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