236 lines
6.8 KiB
C
236 lines
6.8 KiB
C
|
// RUN: %clang_analyze_cc1 -verify %s \
|
||
|
// RUN: -analyzer-checker=core \
|
||
|
// RUN: -analyzer-checker=alpha.unix.Stream \
|
||
|
// RUN: -analyzer-checker=debug.StreamTester \
|
||
|
// RUN: -analyzer-checker=debug.ExprInspection
|
||
|
|
||
|
#include "Inputs/system-header-simulator.h"
|
||
|
|
||
|
void clang_analyzer_eval(int);
|
||
|
void clang_analyzer_warnIfReached();
|
||
|
void StreamTesterChecker_make_feof_stream(FILE *);
|
||
|
void StreamTesterChecker_make_ferror_stream(FILE *);
|
||
|
|
||
|
void error_fopen() {
|
||
|
FILE *F = fopen("file", "r");
|
||
|
if (!F)
|
||
|
return;
|
||
|
clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}}
|
||
|
clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
|
||
|
fclose(F);
|
||
|
}
|
||
|
|
||
|
void error_freopen() {
|
||
|
FILE *F = fopen("file", "r");
|
||
|
if (!F)
|
||
|
return;
|
||
|
F = freopen(0, "w", F);
|
||
|
if (!F)
|
||
|
return;
|
||
|
clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}}
|
||
|
clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
|
||
|
fclose(F);
|
||
|
}
|
||
|
|
||
|
void stream_error_feof() {
|
||
|
FILE *F = fopen("file", "r");
|
||
|
if (!F)
|
||
|
return;
|
||
|
StreamTesterChecker_make_feof_stream(F);
|
||
|
clang_analyzer_eval(feof(F)); // expected-warning {{TRUE}}
|
||
|
clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
|
||
|
clearerr(F);
|
||
|
clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}}
|
||
|
clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
|
||
|
fclose(F);
|
||
|
}
|
||
|
|
||
|
void stream_error_ferror() {
|
||
|
FILE *F = fopen("file", "r");
|
||
|
if (!F)
|
||
|
return;
|
||
|
StreamTesterChecker_make_ferror_stream(F);
|
||
|
clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}}
|
||
|
clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}}
|
||
|
clearerr(F);
|
||
|
clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}}
|
||
|
clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
|
||
|
fclose(F);
|
||
|
}
|
||
|
|
||
|
void error_fread() {
|
||
|
FILE *F = tmpfile();
|
||
|
if (!F)
|
||
|
return;
|
||
|
char Buf[10];
|
||
|
int Ret = fread(Buf, 1, 10, F);
|
||
|
if (Ret == 10) {
|
||
|
clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{FALSE}}
|
||
|
} else {
|
||
|
clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{TRUE}}
|
||
|
if (feof(F)) {
|
||
|
clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
|
||
|
fread(Buf, 1, 10, F); // expected-warning {{Read function called when stream is in EOF state}}
|
||
|
clang_analyzer_eval(feof(F)); // expected-warning {{TRUE}}
|
||
|
clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
|
||
|
}
|
||
|
if (ferror(F)) {
|
||
|
clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
|
||
|
fread(Buf, 1, 10, F); // expected-warning {{might be 'indeterminate'}}
|
||
|
}
|
||
|
}
|
||
|
fclose(F);
|
||
|
Ret = fread(Buf, 1, 10, F); // expected-warning {{Stream might be already closed}}
|
||
|
}
|
||
|
|
||
|
void error_fwrite() {
|
||
|
FILE *F = tmpfile();
|
||
|
if (!F)
|
||
|
return;
|
||
|
const char *Buf = "123456789";
|
||
|
int Ret = fwrite(Buf, 1, 10, F);
|
||
|
if (Ret == 10) {
|
||
|
clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{FALSE}}
|
||
|
} else {
|
||
|
clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}}
|
||
|
clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}}
|
||
|
fwrite(0, 1, 10, F); // expected-warning {{might be 'indeterminate'}}
|
||
|
}
|
||
|
fclose(F);
|
||
|
Ret = fwrite(0, 1, 10, F); // expected-warning {{Stream might be already closed}}
|
||
|
}
|
||
|
|
||
|
void freadwrite_zerosize(FILE *F) {
|
||
|
fwrite(0, 1, 0, F);
|
||
|
fwrite(0, 0, 1, F);
|
||
|
fread(0, 1, 0, F);
|
||
|
fread(0, 0, 1, F);
|
||
|
}
|
||
|
|
||
|
void freadwrite_zerosize_eofstate(FILE *F) {
|
||
|
fwrite(0, 1, 0, F);
|
||
|
fwrite(0, 0, 1, F);
|
||
|
fread(0, 1, 0, F); // expected-warning {{Read function called when stream is in EOF state}}
|
||
|
fread(0, 0, 1, F); // expected-warning {{Read function called when stream is in EOF state}}
|
||
|
}
|
||
|
|
||
|
void error_fread_fwrite_zerosize() {
|
||
|
FILE *F = fopen("file", "r");
|
||
|
if (!F)
|
||
|
return;
|
||
|
|
||
|
freadwrite_zerosize(F);
|
||
|
clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}}
|
||
|
clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
|
||
|
|
||
|
StreamTesterChecker_make_ferror_stream(F);
|
||
|
freadwrite_zerosize(F);
|
||
|
clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}}
|
||
|
clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}}
|
||
|
|
||
|
StreamTesterChecker_make_feof_stream(F);
|
||
|
freadwrite_zerosize_eofstate(F);
|
||
|
clang_analyzer_eval(feof(F)); // expected-warning {{TRUE}}
|
||
|
clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
|
||
|
|
||
|
fclose(F);
|
||
|
}
|
||
|
|
||
|
void error_fseek() {
|
||
|
FILE *F = fopen("file", "r");
|
||
|
if (!F)
|
||
|
return;
|
||
|
int rc = fseek(F, 0, SEEK_SET);
|
||
|
if (rc) {
|
||
|
int IsFEof = feof(F), IsFError = ferror(F);
|
||
|
// Get feof or ferror or no error.
|
||
|
clang_analyzer_eval(IsFEof || IsFError);
|
||
|
// expected-warning@-1 {{FALSE}}
|
||
|
// expected-warning@-2 {{TRUE}}
|
||
|
clang_analyzer_eval(IsFEof && IsFError); // expected-warning {{FALSE}}
|
||
|
// Error flags should not change.
|
||
|
if (IsFEof)
|
||
|
clang_analyzer_eval(feof(F)); // expected-warning {{TRUE}}
|
||
|
else
|
||
|
clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}}
|
||
|
if (IsFError)
|
||
|
clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}}
|
||
|
else
|
||
|
clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
|
||
|
} else {
|
||
|
clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}}
|
||
|
clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
|
||
|
// Error flags should not change.
|
||
|
clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}}
|
||
|
clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
|
||
|
}
|
||
|
fclose(F);
|
||
|
}
|
||
|
|
||
|
void error_indeterminate() {
|
||
|
FILE *F = fopen("file", "r+");
|
||
|
if (!F)
|
||
|
return;
|
||
|
const char *Buf = "123456789";
|
||
|
int rc = fseek(F, 0, SEEK_SET);
|
||
|
if (rc) {
|
||
|
if (feof(F)) {
|
||
|
fwrite(Buf, 1, 10, F); // no warning
|
||
|
} else if (ferror(F)) {
|
||
|
fwrite(Buf, 1, 10, F); // expected-warning {{might be 'indeterminate'}}
|
||
|
} else {
|
||
|
fwrite(Buf, 1, 10, F); // expected-warning {{might be 'indeterminate'}}
|
||
|
}
|
||
|
}
|
||
|
fclose(F);
|
||
|
}
|
||
|
|
||
|
void error_indeterminate_clearerr() {
|
||
|
FILE *F = fopen("file", "r+");
|
||
|
if (!F)
|
||
|
return;
|
||
|
const char *Buf = "123456789";
|
||
|
int rc = fseek(F, 0, SEEK_SET);
|
||
|
if (rc) {
|
||
|
if (feof(F)) {
|
||
|
clearerr(F);
|
||
|
fwrite(Buf, 1, 10, F); // no warning
|
||
|
} else if (ferror(F)) {
|
||
|
clearerr(F);
|
||
|
fwrite(Buf, 1, 10, F); // expected-warning {{might be 'indeterminate'}}
|
||
|
} else {
|
||
|
clearerr(F);
|
||
|
fwrite(Buf, 1, 10, F); // expected-warning {{might be 'indeterminate'}}
|
||
|
}
|
||
|
}
|
||
|
fclose(F);
|
||
|
}
|
||
|
|
||
|
void error_indeterminate_feof1() {
|
||
|
FILE *F = fopen("file", "r+");
|
||
|
if (!F)
|
||
|
return;
|
||
|
char Buf[10];
|
||
|
if (fread(Buf, 1, 10, F) < 10) {
|
||
|
if (feof(F)) {
|
||
|
// error is feof, should be non-indeterminate
|
||
|
fwrite("1", 1, 1, F); // no warning
|
||
|
}
|
||
|
}
|
||
|
fclose(F);
|
||
|
}
|
||
|
|
||
|
void error_indeterminate_feof2() {
|
||
|
FILE *F = fopen("file", "r+");
|
||
|
if (!F)
|
||
|
return;
|
||
|
char Buf[10];
|
||
|
if (fread(Buf, 1, 10, F) < 10) {
|
||
|
if (ferror(F) == 0) {
|
||
|
// error is feof, should be non-indeterminate
|
||
|
fwrite("1", 1, 1, F); // no warning
|
||
|
}
|
||
|
}
|
||
|
fclose(F);
|
||
|
}
|