276 lines · c
1// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Stream -analyzer-output text \2// RUN: -analyzer-config unix.Stream:Pedantic=true \3// RUN: -verify %s4// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Stream,unix.StdCLibraryFunctions -analyzer-output text \5// RUN: -analyzer-config unix.Stream:Pedantic=true \6// RUN: -analyzer-config unix.StdCLibraryFunctions:ModelPOSIX=true -verify=expected,stdargs %s7 8#include "Inputs/system-header-simulator.h"9 10void check_note_at_correct_open(void) {11 FILE *F1 = tmpfile(); // expected-note {{Stream opened here}}12 // stdargs-note@-1 {{'tmpfile' is successful}}13 if (!F1)14 // expected-note@-1 {{'F1' is non-null}}15 // expected-note@-2 {{Taking false branch}}16 return;17 FILE *F2 = tmpfile();18 if (!F2) {19 // expected-note@-1 {{'F2' is non-null}}20 // expected-note@-2 {{Taking false branch}}21 fclose(F1);22 return;23 }24 rewind(F2);25 fclose(F2);26 rewind(F1);27}28// expected-warning@-1 {{Opened stream never closed. Potential resource leak}}29// expected-note@-2 {{Opened stream never closed. Potential resource leak}}30 31void check_note_fopen(void) {32 FILE *F = fopen("file", "r"); // expected-note {{Stream opened here}}33 // stdargs-note@-1 {{'fopen' is successful}}34 if (!F)35 // expected-note@-1 {{'F' is non-null}}36 // expected-note@-2 {{Taking false branch}}37 return;38}39// expected-warning@-1 {{Opened stream never closed. Potential resource leak}}40// expected-note@-2 {{Opened stream never closed. Potential resource leak}}41 42void check_note_freopen(void) {43 FILE *F = fopen("file", "r"); // expected-note {{Stream opened here}}44 // stdargs-note@-1 {{'fopen' is successful}}45 if (!F)46 // expected-note@-1 {{'F' is non-null}}47 // expected-note@-2 {{Taking false branch}}48 return;49 F = freopen(0, "w", F); // expected-note {{Stream reopened here}}50 // stdargs-note@-1 {{'freopen' is successful}}51 if (!F)52 // expected-note@-1 {{'F' is non-null}}53 // expected-note@-2 {{Taking false branch}}54 return;55}56// expected-warning@-1 {{Opened stream never closed. Potential resource leak}}57// expected-note@-2 {{Opened stream never closed. Potential resource leak}}58 59void check_note_fdopen(int fd) {60 FILE *F = fdopen(fd, "r"); // expected-note {{Stream opened here}}61 // stdargs-note@-1 {{'fdopen' is successful}}62 if (!F)63 // expected-note@-1 {{'F' is non-null}}64 // expected-note@-2 {{Taking false branch}}65 return;66}67// expected-warning@-1 {{Opened stream never closed. Potential resource leak}}68// expected-note@-2 {{Opened stream never closed. Potential resource leak}}69 70void check_note_leak_2(int c) {71 FILE *F1 = fopen("foo1.c", "r"); // expected-note {{Stream opened here}}72 // stdargs-note@-1 {{'fopen' is successful}}73 if (!F1)74 // expected-note@-1 {{'F1' is non-null}}75 // expected-note@-2 {{Taking false branch}}76 // expected-note@-3 {{'F1' is non-null}}77 // expected-note@-4 {{Taking false branch}}78 return;79 FILE *F2 = fopen("foo2.c", "r"); // expected-note {{Stream opened here}}80 // stdargs-note@-1 {{'fopen' is successful}}81 if (!F2) {82 // expected-note@-1 {{'F2' is non-null}}83 // expected-note@-2 {{Taking false branch}}84 // expected-note@-3 {{'F2' is non-null}}85 // expected-note@-4 {{Taking false branch}}86 fclose(F1);87 return;88 }89 if (c)90 // expected-note@-1 {{Assuming 'c' is not equal to 0}}91 // expected-note@-2 {{Taking true branch}}92 // expected-note@-3 {{Assuming 'c' is not equal to 0}}93 // expected-note@-4 {{Taking true branch}}94 return;95 // expected-warning@-1 {{Opened stream never closed. Potential resource leak}}96 // expected-note@-2 {{Opened stream never closed. Potential resource leak}}97 // expected-warning@-3 {{Opened stream never closed. Potential resource leak}}98 // expected-note@-4 {{Opened stream never closed. Potential resource leak}}99 fclose(F1);100 fclose(F2);101}102 103void check_track_null(void) {104 FILE *F;105 F = fopen("foo1.c", "r"); // expected-note {{Value assigned to 'F'}} expected-note {{Assuming pointer value is null}}106 // stdargs-note@-1 {{'fopen' fails}}107 if (F != NULL) { // expected-note {{Taking false branch}} expected-note {{'F' is equal to NULL}}108 fclose(F);109 return;110 }111 fclose(F); // expected-warning {{Stream pointer might be NULL}}112 // expected-note@-1 {{Stream pointer might be NULL}}113}114 115void check_eof_notes_feof_after_feof(void) {116 FILE *F;117 char Buf[10];118 F = fopen("foo1.c", "r");119 if (F == NULL) { // expected-note {{Taking false branch}} expected-note {{'F' is not equal to NULL}}120 return;121 }122 fread(Buf, 1, 1, F);123 if (feof(F)) { // expected-note {{Taking true branch}}124 clearerr(F);125 fread(Buf, 1, 1, F); // expected-note {{Assuming stream reaches end-of-file here}}126 if (feof(F)) { // expected-note {{Taking true branch}}127 fread(Buf, 1, 1, F); // expected-warning {{Read function called when stream is in EOF state. Function has no effect}}128 // expected-note@-1 {{Read function called when stream is in EOF state. Function has no effect}}129 }130 }131 fclose(F);132}133 134void check_eof_notes_feof_after_no_feof(void) {135 FILE *F;136 char Buf[10];137 F = fopen("foo1.c", "r");138 if (F == NULL) { // expected-note {{Taking false branch}} expected-note {{'F' is not equal to NULL}}139 return;140 }141 fread(Buf, 1, 1, F);142 if (feof(F)) { // expected-note {{Taking false branch}}143 fclose(F);144 return;145 } else if (ferror(F)) { // expected-note {{Taking false branch}}146 fclose(F);147 return;148 }149 fread(Buf, 1, 1, F); // expected-note {{Assuming stream reaches end-of-file here}}150 if (feof(F)) { // expected-note {{Taking true branch}}151 fread(Buf, 1, 1, F); // expected-warning {{Read function called when stream is in EOF state. Function has no effect}}152 // expected-note@-1 {{Read function called when stream is in EOF state. Function has no effect}}153 }154 fclose(F);155}156 157void check_eof_notes_feof_or_no_error(void) {158 FILE *F;159 char Buf[10];160 F = fopen("foo1.c", "r");161 if (F == NULL) // expected-note {{Taking false branch}} expected-note {{'F' is not equal to NULL}}162 return;163 int RRet = fread(Buf, 1, 1, F); // expected-note {{Assuming stream reaches end-of-file here}}164 if (ferror(F)) { // expected-note {{Taking false branch}}165 } else {166 fread(Buf, 1, 1, F); // expected-warning {{Read function called when stream is in EOF state. Function has no effect}}167 // expected-note@-1 {{Read function called when stream is in EOF state. Function has no effect}}168 }169 fclose(F);170}171 172void check_indeterminate_notes(void) {173 FILE *F;174 F = fopen("foo1.c", "r");175 if (F == NULL) // expected-note {{Taking false branch}} \176 // expected-note {{'F' is not equal to NULL}}177 return;178 int R = fgetc(F); // no note179 if (R >= 0) { // expected-note {{Taking true branch}} \180 // expected-note {{'R' is >= 0}}181 fgetc(F); // expected-note {{Assuming this stream operation fails}}182 if (ferror(F)) // expected-note {{Taking true branch}}183 fgetc(F); // expected-warning {{File position of the stream might be 'indeterminate' after a failed operation. Can cause undefined behavior}} \184 // expected-note {{File position of the stream might be 'indeterminate' after a failed operation. Can cause undefined behavior}}185 }186 fclose(F);187}188 189void check_indeterminate_after_clearerr(void) {190 FILE *F;191 char Buf[10];192 F = fopen("foo1.c", "r");193 if (F == NULL) // expected-note {{Taking false branch}} \194 // expected-note {{'F' is not equal to NULL}}195 return;196 fread(Buf, 1, 1, F); // expected-note {{Assuming this stream operation fails}}197 if (ferror(F)) { // expected-note {{Taking true branch}}198 clearerr(F);199 fread(Buf, 1, 1, F); // expected-warning {{might be 'indeterminate' after a failed operation}} \200 // expected-note {{might be 'indeterminate' after a failed operation}}201 }202 fclose(F);203}204 205void check_indeterminate_eof(void) {206 FILE *F;207 char Buf[2];208 F = fopen("foo1.c", "r");209 if (F == NULL) // expected-note {{Taking false branch}} \210 // expected-note {{'F' is not equal to NULL}} \211 // expected-note {{Taking false branch}} \212 // expected-note {{'F' is not equal to NULL}}213 return;214 fgets(Buf, sizeof(Buf), F); // expected-note {{Assuming this stream operation fails}} \215 // expected-note {{Assuming stream reaches end-of-file here}}216 217 fgets(Buf, sizeof(Buf), F); // expected-warning {{might be 'indeterminate'}} \218 // expected-note {{might be 'indeterminate'}} \219 // expected-warning {{stream is in EOF state}} \220 // expected-note {{stream is in EOF state}}221 fclose(F);222}223 224void check_indeterminate_fseek(void) {225 FILE *F = fopen("file", "r");226 if (!F) // expected-note {{Taking false branch}} \227 // expected-note {{'F' is non-null}}228 return;229 int Ret = fseek(F, 1, SEEK_SET); // expected-note {{Assuming this stream operation fails}}230 if (Ret) { // expected-note {{Taking true branch}} \231 // expected-note {{'Ret' is -1}}232 char Buf[2];233 fwrite(Buf, 1, 2, F); // expected-warning {{might be 'indeterminate'}} \234 // expected-note {{might be 'indeterminate'}}235 }236 fclose(F);237}238 239void error_fseek_ftell(void) {240 FILE *F = fopen("file", "r");241 if (!F) // expected-note {{Taking false branch}} \242 // expected-note {{'F' is non-null}}243 return;244 fseek(F, 0, SEEK_END); // expected-note {{Assuming this stream operation fails}}245 long size = ftell(F); // expected-warning {{might be 'indeterminate'}} \246 // expected-note {{might be 'indeterminate'}}247 if (size == -1) {248 fclose(F);249 return;250 }251 if (size == 1)252 fprintf(F, "abcd");253 fclose(F);254}255 256void error_fseek_read_eof(void) {257 FILE *F = fopen("file", "r");258 if (!F)259 return;260 if (fseek(F, 22, SEEK_SET) == -1) {261 fclose(F);262 return;263 }264 fgetc(F); // no warning265 fclose(F);266}267 268void check_note_at_use_after_close(void) {269 FILE *F = tmpfile();270 if (!F) // expected-note {{'F' is non-null}} expected-note {{Taking false branch}}271 return;272 fclose(F); // expected-note {{Stream is closed here}}273 rewind(F); // expected-warning {{Use of a stream that might be already closed}}274 // expected-note@-1 {{Use of a stream that might be already closed}}275}276