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