New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[clang][analyzer] Support 'tello' and 'fseeko' in the StreamChecker #77580
Conversation
@llvm/pr-subscribers-clang @llvm/pr-subscribers-clang-static-analyzer-1 Author: Ben Shi (benshi001) ChangesFull diff: https://github.com/llvm/llvm-project/pull/77580.diff 3 Files Affected:
diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
index fbfa101257d5e1..f6e6f3122f3aa7 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},
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..1b14fc2eee2003 100644
--- a/clang/test/Analysis/stream-error.c
+++ b/clang/test/Analysis/stream-error.c
@@ -295,6 +295,37 @@ 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@-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_fseek_0(void) {
FILE *F = fopen("file", "r");
if (!F)
@@ -324,6 +355,57 @@ 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@-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_ftell(void) {
+ FILE *F = fopen("file", "r");
+ if (!F)
+ return;
+ long Ret = ftell(F);
+ if (!(Ret >= 0)) {
+ clang_analyzer_eval(Ret == -1L); // expected-warning {{TRUE}}
+ }
+ fclose(F);
+}
+
+void error_ftello(void) {
+ FILE *F = fopen("file", "r");
+ if (!F)
+ return;
+ off_t Ret = ftello(F);
+ if (!(Ret == -1)) {
+ clang_analyzer_eval(Ret >= 0); // expected-warning {{TRUE}}
+ }
+ fclose(F);
+}
+
void error_fflush_after_fclose(void) {
FILE *F = tmpfile();
int Ret;
|
It is better to replace in code of |
This has been fixed. Thanks! |
No description provided.