1 // RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Stream -analyzer-output text \ 2 // RUN: -analyzer-config unix.Stream:Pedantic=true \ 3 // RUN: -verify %s 4 // 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 %s 7 8 #include "Inputs/system-header-simulator.h" 9 10 void 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 31 void 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 42 void 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 59 void 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 70 void 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 103 void 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 115 void 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 134 void 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 157 void 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 172 void 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 note 179 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 189 void 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 205 void 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 224 void 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 239 void 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 256 void 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 warning 265 fclose(F); 266 } 267 268 void 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