https://github.com/benshi001 created https://github.com/llvm/llvm-project/pull/77580
None >From cb79cad6837dba5d33476c65923ec714507a3fef Mon Sep 17 00:00:00 2001 From: Ben Shi <benn...@tencent.com> Date: Wed, 10 Jan 2024 19:00:27 +0800 Subject: [PATCH] [clang][analyzer] Support 'tello' and 'fseeko' in the StreamChecker --- .../StaticAnalyzer/Checkers/StreamChecker.cpp | 4 + .../Analysis/Inputs/system-header-simulator.h | 3 + clang/test/Analysis/stream-error.c | 82 +++++++++++++++++++ 3 files changed, 89 insertions(+) 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; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits