[clang] 19081f4 - [clang][analyzer] Support 'tello' and 'fseeko' in the StreamChecker (#77580)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Jan 11 02:48:35 PST 2024
Author: Ben Shi
Date: 2024-01-11T18:48:31+08:00
New Revision: 19081f4a504053f551eb88bfa8a09a075c826e64
URL: https://github.com/llvm/llvm-project/commit/19081f4a504053f551eb88bfa8a09a075c826e64
DIFF: https://github.com/llvm/llvm-project/commit/19081f4a504053f551eb88bfa8a09a075c826e64.diff
LOG: [clang][analyzer] Support 'tello' and 'fseeko' in the StreamChecker (#77580)
Added:
Modified:
clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
clang/test/Analysis/Inputs/system-header-simulator.h
clang/test/Analysis/stream-error.c
Removed:
################################################################################
diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
index fbfa101257d5e1..742426a628e065 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
@@ -268,8 +268,12 @@ class StreamChecker : public Checker<check::PreCall, eval::Call,
std::bind(&StreamChecker::evalUngetc, _1, _2, _3, _4), 1}},
{{{"fseek"}, 3},
{&StreamChecker::preFseek, &StreamChecker::evalFseek, 0}},
+ {{{"fseeko"}, 3},
+ {&StreamChecker::preFseek, &StreamChecker::evalFseek, 0}},
{{{"ftell"}, 1},
{&StreamChecker::preDefault, &StreamChecker::evalFtell, 0}},
+ {{{"ftello"}, 1},
+ {&StreamChecker::preDefault, &StreamChecker::evalFtell, 0}},
{{{"fflush"}, 1},
{&StreamChecker::preFflush, &StreamChecker::evalFflush, 0}},
{{{"rewind"}, 1},
@@ -1113,10 +1117,10 @@ void StreamChecker::evalFtell(const FnDescription *Desc, const CallEvent &Call,
NonLoc RetVal = makeRetVal(C, CE).castAs<NonLoc>();
ProgramStateRef StateNotFailed =
State->BindExpr(CE, C.getLocationContext(), RetVal);
- auto Cond = SVB.evalBinOp(State, BO_GE, RetVal,
- SVB.makeZeroVal(C.getASTContext().LongTy),
- SVB.getConditionType())
- .getAs<DefinedOrUnknownSVal>();
+ auto Cond =
+ SVB.evalBinOp(State, BO_GE, RetVal, SVB.makeZeroVal(Call.getResultType()),
+ SVB.getConditionType())
+ .getAs<DefinedOrUnknownSVal>();
if (!Cond)
return;
StateNotFailed = StateNotFailed->assume(*Cond, true);
@@ -1124,7 +1128,7 @@ void StreamChecker::evalFtell(const FnDescription *Desc, const CallEvent &Call,
return;
ProgramStateRef StateFailed = State->BindExpr(
- CE, C.getLocationContext(), SVB.makeIntVal(-1, C.getASTContext().LongTy));
+ CE, C.getLocationContext(), SVB.makeIntVal(-1, Call.getResultType()));
// This function does not affect the stream state.
// Still we add success and failure state with the appropriate return value.
diff --git a/clang/test/Analysis/Inputs/system-header-simulator.h b/clang/test/Analysis/Inputs/system-header-simulator.h
index caae59c38a4c8e..cd7ac616bcc67f 100644
--- a/clang/test/Analysis/Inputs/system-header-simulator.h
+++ b/clang/test/Analysis/Inputs/system-header-simulator.h
@@ -13,6 +13,7 @@ typedef __typeof(sizeof(int)) size_t;
typedef long long __int64_t;
typedef __int64_t __darwin_off_t;
typedef __darwin_off_t fpos_t;
+typedef int off_t;
typedef struct _FILE FILE;
#define SEEK_SET 0 /* Seek from beginning of file. */
@@ -55,7 +56,9 @@ int fputc(int ch, FILE *stream);
int fputs(const char *restrict s, FILE *restrict stream);
int ungetc(int c, FILE *stream);
int fseek(FILE *__stream, long int __off, int __whence);
+int fseeko(FILE *__stream, off_t __off, int __whence);
long int ftell(FILE *__stream);
+off_t ftello(FILE *__stream);
void rewind(FILE *__stream);
int fgetpos(FILE *restrict stream, fpos_t *restrict pos);
int fsetpos(FILE *stream, const fpos_t *pos);
diff --git a/clang/test/Analysis/stream-error.c b/clang/test/Analysis/stream-error.c
index c038348e799d29..2d03c0bbe7c474 100644
--- a/clang/test/Analysis/stream-error.c
+++ b/clang/test/Analysis/stream-error.c
@@ -295,6 +295,25 @@ void error_fseek(void) {
fclose(F);
}
+void error_fseeko(void) {
+ FILE *F = fopen("file", "r");
+ if (!F)
+ return;
+ int rc = fseeko(F, 1, 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 at -1 {{FALSE}}
+ // expected-warning at -2 {{TRUE}}
+ clang_analyzer_eval(IsFEof && IsFError); // 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)
@@ -324,6 +343,68 @@ void error_fseek_0(void) {
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 at -1 {{FALSE}}
+ // expected-warning at -2 {{TRUE}}
+ clang_analyzer_eval(IsFEof);
+ // expected-warning at -1 {{FALSE}}
+ } else {
+ clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}}
+ clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
+ }
+ fclose(F);
+}
+
+void error_ftell(void) {
+ 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}}
+ fclose(F);
+}
+
+void error_ftello(void) {
+ 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}}
+ fclose(F);
+}
+
void error_fflush_after_fclose(void) {
FILE *F = tmpfile();
int Ret;
More information about the cfe-commits
mailing list