Files
clang-p2996/clang/test/Analysis/stream-error.c
Balázs Kéri 5cf85323a0 [clang][analyzer] Extend StreamChecker with some new functions.
The stream handling functions `ftell`, `rewind`, `fgetpos`, `fsetpos`
are evaluated in the checker more exactly than before.
New tests are added to test behavior of the checker together with
StdLibraryFunctionsChecker. The option ModelPOSIX of that checker
affects if (most of) the stream functions are recognized, and checker
StdLibraryFunctionArgs generates warnings if constraints for arguments
are not satisfied. The state of `errno` is set by StdLibraryFunctionsChecker
too for every case in the stream functions.
StreamChecker works with the stream state only, does not set the errno state,
and is not dependent on other checkers.

Reviewed By: Szelethus

Differential Revision: https://reviews.llvm.org/D140395
2023-01-06 12:22:21 +01:00

242 lines
7.1 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_dump(int);
void clang_analyzer_warnIfReached(void);
void StreamTesterChecker_make_feof_stream(FILE *);
void StreamTesterChecker_make_ferror_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_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}}
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}}
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 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, 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(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);
}