| // RUN: %clang_analyze_cc1 -verify %s -analyzer-output=text \ | |
| // RUN: -analyzer-checker=core \ | |
| // RUN: -analyzer-checker=unix.Stream | |
| #include "Inputs/system-header-simulator.h" | |
| char *logDump(); | |
| bool coin(); | |
| [[noreturn]] void halt(); | |
| void assert(bool b) { | |
| if (!b) | |
| halt(); | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // Report for which we expect NoOwnershipChangeVisitor to add a new note. | |
| //===----------------------------------------------------------------------===// | |
| namespace stream_opened_in_fn_call { | |
| // TODO: AST analysis of sink would reveal that it doesn't intent to free the | |
| // allocated memory, but in this instance, its also the only function with | |
| // the ability to do so, we should see a note here. | |
| void sink(FILE *f) { | |
| } | |
| void f() { | |
| sink(fopen("input.txt", "w")); | |
| // expected-note@-1{{Stream opened here}} | |
| } // expected-warning{{Opened stream never closed. Potential resource leak [unix.Stream]}} | |
| // expected-note@-1{{Opened stream never closed. Potential resource leak}} | |
| } // namespace stream_opened_in_fn_call | |
| namespace stream_passed_to_fn_call { | |
| void expectedClose(FILE *f) { | |
| if (char *log = logDump()) { // expected-note{{Assuming 'log' is null}} | |
| // expected-note@-1{{Taking false branch}} | |
| printf("%s", log); | |
| fclose(f); | |
| } | |
| } // expected-note{{Returning without closing stream object or storing it for later release}} | |
| void f() { | |
| FILE *f = fopen("input.txt", "w"); // expected-note{{Stream opened here}} | |
| if (!f) // expected-note{{'f' is non-null}} | |
| // expected-note@-1{{Taking false branch}} | |
| return; | |
| if (coin()) { // expected-note{{Assuming the condition is true}} | |
| // expected-note@-1{{Taking true branch}} | |
| expectedClose(f); // expected-note{{Calling 'expectedClose'}} | |
| // expected-note@-1{{Returning from 'expectedClose'}} | |
| return; // expected-warning{{Opened stream never closed. Potential resource leak [unix.Stream]}} | |
| // expected-note@-1{{Opened stream never closed. Potential resource leak}} | |
| } | |
| fclose(f); | |
| } | |
| } // namespace stream_passed_to_fn_call | |
| namespace stream_shared_with_ptr_of_shorter_lifetime { | |
| void sink(FILE *f) { | |
| FILE *Q = f; | |
| if (coin()) // expected-note {{Assuming the condition is false}} | |
| // expected-note@-1 {{Taking false branch}} | |
| fclose(f); | |
| (void)Q; | |
| } // expected-note{{Returning without closing stream object or storing it for later release}} | |
| void foo() { | |
| FILE *f = fopen("input.txt", "w"); // expected-note{{Stream opened here}} | |
| if (!f) // expected-note{{'f' is non-null}} | |
| // expected-note@-1{{Taking false branch}} | |
| return; | |
| sink(f); // expected-note {{Calling 'sink'}} | |
| // expected-note@-1 {{Returning from 'sink'}} | |
| } // expected-warning{{Opened stream never closed. Potential resource leak [unix.Stream]}} | |
| // expected-note@-1{{Opened stream never closed. Potential resource leak}} | |
| } // namespace stream_shared_with_ptr_of_shorter_lifetime | |
| //===----------------------------------------------------------------------===// | |
| // Report for which we *do not* expect NoOwnershipChangeVisitor add a new note, | |
| // nor do we want it to. | |
| //===----------------------------------------------------------------------===// | |
| namespace stream_not_passed_to_fn_call { | |
| void expectedClose(FILE *f) { | |
| if (char *log = logDump()) { | |
| printf("%s", log); | |
| fclose(f); | |
| } | |
| } | |
| void f(FILE *p) { | |
| FILE *f = fopen("input.txt", "w"); // expected-note{{Stream opened here}} | |
| if (!f) // expected-note{{'f' is non-null}} | |
| // expected-note@-1{{Taking false branch}} | |
| return; | |
| expectedClose(p); // expected-warning{{Opened stream never closed. Potential resource leak [unix.Stream]}} | |
| // expected-note@-1{{Opened stream never closed. Potential resource leak}} | |
| } | |
| } // namespace stream_not_passed_to_fn_call | |
| namespace stream_shared_with_ptr_of_same_lifetime { | |
| void expectedClose(FILE *f, FILE **p) { | |
| // NOTE: Not a job of NoOwnershipChangeVisitor, but maybe this could be | |
| // highlighted still? | |
| *p = f; | |
| } | |
| void f() { | |
| FILE *f = fopen("input.txt", "w"); // expected-note{{Stream opened here}} | |
| FILE *p = NULL; | |
| if (!f) // expected-note{{'f' is non-null}} | |
| // expected-note@-1{{Taking false branch}} | |
| return; | |
| expectedClose(f, &p); | |
| } // expected-warning{{Opened stream never closed. Potential resource leak [unix.Stream]}} | |
| // expected-note@-1{{Opened stream never closed. Potential resource leak}} | |
| } // namespace stream_shared_with_ptr_of_same_lifetime | |
| namespace stream_passed_into_fn_that_doesnt_intend_to_free { | |
| void expectedClose(FILE *f) { | |
| } | |
| void f() { | |
| FILE *f = fopen("input.txt", "w"); // expected-note{{Stream opened here}} | |
| if (!f) // expected-note{{'f' is non-null}} | |
| // expected-note@-1{{Taking false branch}} | |
| return; | |
| expectedClose(f); | |
| } // expected-warning{{Opened stream never closed. Potential resource leak [unix.Stream]}} | |
| // expected-note@-1{{Opened stream never closed. Potential resource leak}} | |
| } // namespace stream_passed_into_fn_that_doesnt_intend_to_free | |
| namespace stream_passed_into_fn_that_doesnt_intend_to_free2 { | |
| void bar(); | |
| void expectedClose(FILE *f) { | |
| // Correctly realize that calling bar() doesn't mean that this function would | |
| // like to deallocate anything. | |
| bar(); | |
| } | |
| void f() { | |
| FILE *f = fopen("input.txt", "w"); // expected-note{{Stream opened here}} | |
| if (!f) // expected-note{{'f' is non-null}} | |
| // expected-note@-1{{Taking false branch}} | |
| return; | |
| expectedClose(f); | |
| } // expected-warning{{Opened stream never closed. Potential resource leak [unix.Stream]}} | |
| // expected-note@-1{{Opened stream never closed. Potential resource leak}} | |
| } // namespace stream_passed_into_fn_that_doesnt_intend_to_free2 | |
| namespace streamstate_from_closed_to_open { | |
| // StreamState of the symbol changed from nothing to Allocated. We don't want to | |
| // emit notes when the RefKind changes in the stack frame. | |
| static FILE *fopenWrapper() { | |
| FILE *f = fopen("input.txt", "w"); // expected-note{{Stream opened here}} | |
| assert(f); | |
| return f; | |
| } | |
| void use_ret() { | |
| FILE *v; | |
| v = fopenWrapper(); // expected-note {{Calling 'fopenWrapper'}} | |
| // expected-note@-1{{Returning from 'fopenWrapper'}} | |
| } // expected-warning{{Opened stream never closed. Potential resource leak [unix.Stream]}} | |
| // expected-note@-1{{Opened stream never closed. Potential resource leak}} | |
| } // namespace streamstate_from_closed_to_open |