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