[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