blob: 3f791d13346419dee74aec704e4c6034508a5189 [file] [log] [blame]
// RUN: %clang_analyze_cc1 -verify %s \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=unix.Stream \
// RUN: -analyzer-config unix.Stream:Pedantic=true \
// RUN: -analyzer-checker=debug.StreamTester \
// RUN: -analyzer-checker=debug.ExprInspection
#include "Inputs/system-header-simulator.h"
void clang_analyzer_eval(int);
void clang_analyzer_dump(int);
void clang_analyzer_warnIfReached(void);
void StreamTesterChecker_make_feof_stream(FILE *);
void StreamTesterChecker_make_ferror_stream(FILE *);
void StreamTesterChecker_make_ferror_indeterminate_stream(FILE *);
void error_fopen(void) {
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_fdopen(int fd) {
FILE *F = fdopen(fd, "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(void) {
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(void) {
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}}
StreamTesterChecker_make_ferror_indeterminate_stream(F);
clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}}
fclose(F);
}
void stream_error_ferror(void) {
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}}
StreamTesterChecker_make_ferror_indeterminate_stream(F);
clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}}
fclose(F);
}
void error_fread(void) {
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(void) {
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 error_fgetc(void) {
FILE *F = tmpfile();
if (!F)
return;
int Ret = fgetc(F);
if (0 <= Ret && Ret <= 255) {
clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{FALSE}}
} else {
clang_analyzer_eval(Ret == EOF); // expected-warning {{TRUE}}
clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{TRUE}}
if (feof(F)) {
clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
fgetc(F); // expected-warning {{Read function called when stream is in EOF state}}
} else {
clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}}
fgetc(F); // expected-warning {{might be 'indeterminate'}}
}
}
fclose(F);
fgetc(F); // expected-warning {{Stream might be already closed}}
}
void error_fgets(void) {
FILE *F = tmpfile();
char Buf[256];
if (!F)
return;
char *Ret = fgets(Buf, sizeof(Buf), F);
if (Ret == Buf) {
clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{FALSE}}
} else {
clang_analyzer_eval(Ret == NULL); // expected-warning {{TRUE}}
clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{TRUE}}
if (feof(F)) {
clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
fgets(Buf, sizeof(Buf), F); // expected-warning {{Read function called when stream is in EOF state}}
} else {
clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}}
fgets(Buf, sizeof(Buf), F); // expected-warning {{might be 'indeterminate'}}
}
}
fclose(F);
fgets(Buf, sizeof(Buf), F); // expected-warning {{Stream might be already closed}}
}
void error_fputc(int fd) {
FILE *F = fdopen(fd, "w");
if (!F)
return;
int Ret = fputc('X', F);
if (Ret == EOF) {
clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}}
clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}}
fputc('Y', F); // expected-warning {{might be 'indeterminate'}}
} else {
clang_analyzer_eval(Ret == 'X'); // expected-warning {{TRUE}}
clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{FALSE}}
fputc('Y', F); // no-warning
}
fclose(F);
fputc('A', F); // expected-warning {{Stream might be already closed}}
}
void error_fputs(void) {
FILE *F = tmpfile();
if (!F)
return;
int Ret = fputs("XYZ", F);
if (Ret >= 0) {
clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{FALSE}}
fputs("QWD", F); // no-warning
} else {
clang_analyzer_eval(Ret == EOF); // expected-warning {{TRUE}}
clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}}
clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}}
fputs("QWD", F); // expected-warning {{might be 'indeterminate'}}
}
fclose(F);
fputs("ABC", F); // expected-warning {{Stream might be already closed}}
}
void error_fprintf(void) {
FILE *F = tmpfile();
if (!F)
return;
int Ret = fprintf(F, "aaa");
if (Ret >= 0) {
clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{FALSE}}
fprintf(F, "bbb"); // no-warning
} else {
clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}}
clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}}
fprintf(F, "bbb"); // expected-warning {{might be 'indeterminate'}}
}
fclose(F);
fprintf(F, "ccc"); // expected-warning {{Stream might be already closed}}
}
void error_fscanf(int *A) {
FILE *F = tmpfile();
if (!F)
return;
int Ret = fscanf(F, "a%ib", A);
if (Ret >= 0) {
clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{FALSE}}
fscanf(F, "bbb"); // no-warning
} else {
if (ferror(F)) {
clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
fscanf(F, "bbb"); // expected-warning {{might be 'indeterminate'}}
} else if (feof(F)) {
clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
fscanf(F, "bbb"); // expected-warning {{is in EOF state}}
clang_analyzer_eval(feof(F)); // expected-warning {{TRUE}}
} else {
clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
fscanf(F, "bbb"); // expected-warning {{might be 'indeterminate'}}
}
}
fclose(F);
fscanf(F, "ccc"); // expected-warning {{Stream might be already closed}}
}
void error_ungetc(int TestIndeterminate) {
FILE *F = tmpfile();
if (!F)
return;
int Ret = ungetc('X', F);
clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{FALSE}}
if (Ret == EOF) {
clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
} else {
clang_analyzer_eval(Ret == 'X'); // expected-warning {{TRUE}}
}
fputc('Y', F); // no-warning
if (TestIndeterminate) {
StreamTesterChecker_make_ferror_indeterminate_stream(F);
ungetc('X', F); // expected-warning {{might be 'indeterminate'}}
}
fclose(F);
ungetc('A', F); // expected-warning {{Stream might be already closed}}
}
void error_getdelim(char *P, size_t Sz) {
FILE *F = tmpfile();
if (!F)
return;
ssize_t Ret = getdelim(&P, &Sz, '\t', F);
if (Ret >= 0) {
clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{FALSE}}
} else {
clang_analyzer_eval(Ret == -1); // expected-warning {{TRUE}}
clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{TRUE}}
if (feof(F)) {
clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
getdelim(&P, &Sz, '\n', F); // expected-warning {{Read function called when stream is in EOF state}}
} else {
clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}}
getdelim(&P, &Sz, '\n', F); // expected-warning {{might be 'indeterminate'}}
}
}
fclose(F);
getdelim(&P, &Sz, '\n', F); // expected-warning {{Stream might be already closed}}
}
void error_getline(char *P, size_t Sz) {
FILE *F = tmpfile();
if (!F)
return;
ssize_t Ret = getline(&P, &Sz, F);
if (Ret >= 0) {
clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{FALSE}}
} else {
clang_analyzer_eval(Ret == -1); // expected-warning {{TRUE}}
clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{TRUE}}
if (feof(F)) {
clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
getline(&P, &Sz, F); // expected-warning {{Read function called when stream is in EOF state}}
} else {
clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}}
getline(&P, &Sz, F); // expected-warning {{might be 'indeterminate'}}
}
}
fclose(F);
getline(&P, &Sz, F); // expected-warning {{Stream might be already closed}}
}
void write_after_eof_is_allowed(void) {
FILE *F = tmpfile();
if (!F)
return;
StreamTesterChecker_make_feof_stream(F);
if (fputs("QWD", F) >= 0) // no-warning
clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{FALSE}}
StreamTesterChecker_make_feof_stream(F);
if (fputc('Q', F) == 'Q') // no-warning
clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{FALSE}}
StreamTesterChecker_make_feof_stream(F);
if (fwrite("012345678", 1, 10, F) == 10) // no-warning
clang_analyzer_eval(feof(F) || ferror(F)); // expected-warning {{FALSE}}
fclose(F);
}
void freadwrite_zerosize(FILE *F) {
size_t Ret;
Ret = fwrite(0, 1, 0, F);
clang_analyzer_dump(Ret); // expected-warning {{0 }}
Ret = fwrite(0, 0, 1, F);
clang_analyzer_dump(Ret); // expected-warning {{0 }}
Ret = fread(0, 1, 0, F);
clang_analyzer_dump(Ret); // expected-warning {{0 }}
Ret = fread(0, 0, 1, F);
clang_analyzer_dump(Ret); // expected-warning {{0 }}
}
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(void) {
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(void) {
FILE *F = fopen("file", "r");
if (!F)
return;
int rc = fseek(F, 1, SEEK_SET);
if (rc) {
clang_analyzer_eval(rc == -1); // expected-warning {{TRUE}}
int IsFEof = feof(F), IsFError = ferror(F);
// Get ferror or no error.
clang_analyzer_eval(IsFError); // expected-warning {{FALSE}} \
// expected-warning {{TRUE}}
clang_analyzer_eval(IsFEof); // expected-warning {{FALSE}}
// Error flags should not change.
clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}}
if (IsFError)
clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}}
} 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_fseeko(void) {
FILE *F = fopen("file", "r");
if (!F)
return;
int rc = fseeko(F, 1, SEEK_SET);
if (rc) {
// Get ferror or no error.
clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}} \
// expected-warning {{TRUE}}
clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}}
} else {
clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}}
clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
}
fclose(F);
}
void error_fseek_0(void) {
FILE *F = fopen("file", "r");
if (!F)
return;
int rc = fseek(F, 0, SEEK_SET);
if (rc == -1) {
int IsFEof = feof(F), IsFError = ferror(F);
// Get ferror or no error, but not feof.
clang_analyzer_eval(IsFError);
// expected-warning@-1 {{FALSE}}
// expected-warning@-2 {{TRUE}}
clang_analyzer_eval(IsFEof);
// expected-warning@-1 {{FALSE}}
// Error flags should not change.
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_fseeko_0(void) {
FILE *F = fopen("file", "r");
if (!F)
return;
int rc = fseeko(F, 0, SEEK_SET);
if (rc) {
int IsFEof = feof(F), IsFError = ferror(F);
// Get ferror or no error, but not feof.
clang_analyzer_eval(IsFError);
// expected-warning@-1 {{FALSE}}
// expected-warning@-2 {{TRUE}}
clang_analyzer_eval(IsFEof);
// expected-warning@-1 {{FALSE}}
} else {
clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}}
clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
}
fclose(F);
}
void error_ftell(int TestIndeterminate) {
FILE *F = fopen("file", "r");
if (!F)
return;
long rc = ftell(F);
if (rc >= 0)
clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
else
clang_analyzer_eval(rc == -1); // expected-warning {{TRUE}}
clang_analyzer_eval(feof(F) && ferror(F)); // expected-warning {{FALSE}}
StreamTesterChecker_make_feof_stream(F);
rc = ftell(F);
clang_analyzer_eval(feof(F)); // expected-warning {{TRUE}}
clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
StreamTesterChecker_make_ferror_stream(F);
rc = ftell(F);
clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}}
clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}}
if (TestIndeterminate) {
StreamTesterChecker_make_ferror_indeterminate_stream(F);
ftell(F); // expected-warning {{might be 'indeterminate'}}
}
fclose(F);
}
void error_ftello(int TestIndeterminate) {
FILE *F = fopen("file", "r");
if (!F)
return;
off_t rc = ftello(F);
if (rc >= 0)
clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
else
clang_analyzer_eval(rc == -1); // expected-warning {{TRUE}}
clang_analyzer_eval(feof(F) && ferror(F)); // expected-warning {{FALSE}}
StreamTesterChecker_make_feof_stream(F);
rc = ftello(F);
clang_analyzer_eval(feof(F)); // expected-warning {{TRUE}}
clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
StreamTesterChecker_make_ferror_stream(F);
rc = ftello(F);
clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}}
clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}}
if (TestIndeterminate) {
StreamTesterChecker_make_ferror_indeterminate_stream(F);
ftell(F); // expected-warning {{might be 'indeterminate'}}
}
fclose(F);
}
void error_fileno(void) {
FILE *F = fopen("file", "r");
if (!F)
return;
int N = fileno(F);
clang_analyzer_eval(N >= 0); // expected-warning {{TRUE}}
clang_analyzer_eval(feof(F) && ferror(F)); // expected-warning {{FALSE}}
StreamTesterChecker_make_feof_stream(F);
N = fileno(F);
clang_analyzer_eval(feof(F)); // expected-warning {{TRUE}}
clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
StreamTesterChecker_make_ferror_stream(F);
N = fileno(F);
clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}}
clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}}
StreamTesterChecker_make_ferror_indeterminate_stream(F);
fileno(F); // no warning
fclose(F);
}
void error_fflush_on_non_null_stream_clear_error_states(void) {
FILE *F0 = tmpfile(), *F1 = tmpfile();
// `fflush` clears a non-EOF stream's error state.
if (F0) {
StreamTesterChecker_make_ferror_stream(F0);
if (fflush(F0) == 0) { // no-warning
clang_analyzer_eval(ferror(F0)); // expected-warning {{FALSE}}
clang_analyzer_eval(feof(F0)); // expected-warning {{FALSE}}
}
fclose(F0);
}
// `fflush` clears an EOF stream's error state.
if (F1) {
StreamTesterChecker_make_feof_stream(F1);
if (fflush(F1) == 0) { // no-warning
clang_analyzer_eval(ferror(F1)); // expected-warning {{FALSE}}
clang_analyzer_eval(feof(F1)); // expected-warning {{TRUE}}
}
fclose(F1);
}
}
void error_fflush_on_null_stream_clear_error_states(void) {
FILE *F0 = tmpfile(), *F1 = tmpfile();
// `fflush` clears all stream's error states, while retains their EOF states.
if (F0 && F1) {
StreamTesterChecker_make_ferror_stream(F0);
StreamTesterChecker_make_feof_stream(F1);
if (fflush(NULL) == 0) { // no-warning
clang_analyzer_eval(ferror(F0)); // expected-warning {{FALSE}}
clang_analyzer_eval(feof(F0)); // expected-warning {{FALSE}}
clang_analyzer_eval(ferror(F1)); // expected-warning {{FALSE}}
clang_analyzer_eval(feof(F1)); // expected-warning {{TRUE}}
}
}
if (F0)
fclose(F0);
if (F1)
fclose(F1);
}
void error_indeterminate(void) {
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(void) {
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(void) {
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(void) {
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);
}