xref: /llvm-project/clang/test/Analysis/stream-notes-missing-close.cpp (revision fc4b09d16139348533f1a1c9c72c99dacba51417)
1 // RUN: %clang_analyze_cc1 -verify %s -analyzer-output=text \
2 // RUN:   -analyzer-checker=core \
3 // RUN:   -analyzer-checker=unix.Stream
4 
5 
6 #include "Inputs/system-header-simulator.h"
7 char *logDump();
8 bool coin();
9 
10 [[noreturn]] void halt();
11 
assert(bool b)12 void assert(bool b) {
13   if (!b)
14     halt();
15 }
16 
17 //===----------------------------------------------------------------------===//
18 // Report for which we expect NoOwnershipChangeVisitor to add a new note.
19 //===----------------------------------------------------------------------===//
20 
21 namespace stream_opened_in_fn_call {
22 // TODO: AST analysis of sink would reveal that it doesn't intent to free the
23 // allocated memory, but in this instance, its also the only function with
24 // the ability to do so, we should see a note here.
sink(FILE * f)25 void sink(FILE *f) {
26 }
27 
f()28 void f() {
29   sink(fopen("input.txt", "w"));
30   // expected-note@-1{{Stream opened here}}
31 } // expected-warning{{Opened stream never closed. Potential resource leak [unix.Stream]}}
32 // expected-note@-1{{Opened stream never closed. Potential resource leak}}
33 } // namespace stream_opened_in_fn_call
34 
35 namespace stream_passed_to_fn_call {
36 
expectedClose(FILE * f)37 void expectedClose(FILE *f) {
38   if (char *log = logDump()) { // expected-note{{Assuming 'log' is null}}
39                                // expected-note@-1{{Taking false branch}}
40     printf("%s", log);
41     fclose(f);
42   }
43 } // expected-note{{Returning without closing stream object or storing it for later release}}
44 
f()45 void f() {
46   FILE *f = fopen("input.txt", "w"); // expected-note{{Stream opened here}}
47   if (!f) // expected-note{{'f' is non-null}}
48           // expected-note@-1{{Taking false branch}}
49     return;
50   if (coin()) { // expected-note{{Assuming the condition is true}}
51                 // expected-note@-1{{Taking true branch}}
52     expectedClose(f); // expected-note{{Calling 'expectedClose'}}
53                       // expected-note@-1{{Returning from 'expectedClose'}}
54 
55     return; // expected-warning{{Opened stream never closed. Potential resource leak [unix.Stream]}}
56             // expected-note@-1{{Opened stream never closed. Potential resource leak}}
57   }
58   fclose(f);
59 }
60 } // namespace stream_passed_to_fn_call
61 
62 namespace stream_shared_with_ptr_of_shorter_lifetime {
63 
sink(FILE * f)64 void sink(FILE *f) {
65   FILE *Q = f;
66   if (coin()) // expected-note {{Assuming the condition is false}}
67               // expected-note@-1 {{Taking false branch}}
68     fclose(f);
69   (void)Q;
70 } // expected-note{{Returning without closing stream object or storing it for later release}}
71 
foo()72 void foo() {
73   FILE *f = fopen("input.txt", "w"); // expected-note{{Stream opened here}}
74   if (!f) // expected-note{{'f' is non-null}}
75           // expected-note@-1{{Taking false branch}}
76     return;
77   sink(f); // expected-note {{Calling 'sink'}}
78            // expected-note@-1 {{Returning from 'sink'}}
79 } // expected-warning{{Opened stream never closed. Potential resource leak [unix.Stream]}}
80 // expected-note@-1{{Opened stream never closed. Potential resource leak}}
81 
82 } // namespace stream_shared_with_ptr_of_shorter_lifetime
83 
84 //===----------------------------------------------------------------------===//
85 // Report for which we *do not* expect NoOwnershipChangeVisitor add a new note,
86 // nor do we want it to.
87 //===----------------------------------------------------------------------===//
88 
89 namespace stream_not_passed_to_fn_call {
90 
expectedClose(FILE * f)91 void expectedClose(FILE *f) {
92   if (char *log = logDump()) {
93     printf("%s", log);
94     fclose(f);
95   }
96 }
97 
f(FILE * p)98 void f(FILE *p) {
99   FILE *f = fopen("input.txt", "w"); // expected-note{{Stream opened here}}
100   if (!f) // expected-note{{'f' is non-null}}
101           // expected-note@-1{{Taking false branch}}
102     return;
103   expectedClose(p); // expected-warning{{Opened stream never closed. Potential resource leak [unix.Stream]}}
104                     // expected-note@-1{{Opened stream never closed. Potential resource leak}}
105 }
106 } // namespace stream_not_passed_to_fn_call
107 
108 namespace stream_shared_with_ptr_of_same_lifetime {
109 
expectedClose(FILE * f,FILE ** p)110 void expectedClose(FILE *f, FILE **p) {
111   // NOTE: Not a job of NoOwnershipChangeVisitor, but maybe this could be
112   // highlighted still?
113   *p = f;
114 }
115 
f()116 void f() {
117   FILE *f = fopen("input.txt", "w"); // expected-note{{Stream opened here}}
118   FILE *p = NULL;
119   if (!f) // expected-note{{'f' is non-null}}
120           // expected-note@-1{{Taking false branch}}
121     return;
122   expectedClose(f, &p);
123 } // expected-warning{{Opened stream never closed. Potential resource leak [unix.Stream]}}
124   // expected-note@-1{{Opened stream never closed. Potential resource leak}}
125 } // namespace stream_shared_with_ptr_of_same_lifetime
126 
127 namespace stream_passed_into_fn_that_doesnt_intend_to_free {
expectedClose(FILE * f)128 void expectedClose(FILE *f) {
129 }
130 
f()131 void f() {
132   FILE *f = fopen("input.txt", "w"); // expected-note{{Stream opened here}}
133   if (!f) // expected-note{{'f' is non-null}}
134           // expected-note@-1{{Taking false branch}}
135     return;
136   expectedClose(f);
137 
138 } // expected-warning{{Opened stream never closed. Potential resource leak [unix.Stream]}}
139   // expected-note@-1{{Opened stream never closed. Potential resource leak}}
140 } // namespace stream_passed_into_fn_that_doesnt_intend_to_free
141 
142 namespace stream_passed_into_fn_that_doesnt_intend_to_free2 {
143 void bar();
144 
expectedClose(FILE * f)145 void expectedClose(FILE *f) {
146   // Correctly realize that calling bar() doesn't mean that this function would
147   // like to deallocate anything.
148   bar();
149 }
150 
f()151 void f() {
152   FILE *f = fopen("input.txt", "w"); // expected-note{{Stream opened here}}
153   if (!f) // expected-note{{'f' is non-null}}
154           // expected-note@-1{{Taking false branch}}
155     return;
156   expectedClose(f);
157 
158 } // expected-warning{{Opened stream never closed. Potential resource leak [unix.Stream]}}
159   // expected-note@-1{{Opened stream never closed. Potential resource leak}}
160 } // namespace stream_passed_into_fn_that_doesnt_intend_to_free2
161 
162 namespace streamstate_from_closed_to_open {
163 
164 // StreamState of the symbol changed from nothing to Allocated. We don't want to
165 // emit notes when the RefKind changes in the stack frame.
fopenWrapper()166 static FILE *fopenWrapper() {
167   FILE *f = fopen("input.txt", "w"); // expected-note{{Stream opened here}}
168   assert(f);
169   return f;
170 }
use_ret()171 void use_ret() {
172   FILE *v;
173   v = fopenWrapper(); // expected-note {{Calling 'fopenWrapper'}}
174                       // expected-note@-1{{Returning from 'fopenWrapper'}}
175 
176 } // expected-warning{{Opened stream never closed. Potential resource leak [unix.Stream]}}
177   // expected-note@-1{{Opened stream never closed. Potential resource leak}}
178 
179 } // namespace streamstate_from_closed_to_open
180