[clang] [clang][analyzer] Improve modeling of 'fseeko' and 'ftello' in StdLibraryFunctionsChecker (PR #77902)

Ben Shi via cfe-commits cfe-commits at lists.llvm.org
Fri Jan 12 02:19:06 PST 2024


https://github.com/benshi001 created https://github.com/llvm/llvm-project/pull/77902

None

>From 97d753446ffc8eb9c701effb52dd671afc73e1dd Mon Sep 17 00:00:00 2001
From: Ben Shi <bennshi at tencent.com>
Date: Fri, 12 Jan 2024 18:17:39 +0800
Subject: [PATCH] [clang][analyzer] Improve modeling of 'fseeko' and 'ftello'
 in StdLibraryFunctionsChecker

---
 .../Checkers/StdLibraryFunctionsChecker.cpp   | 12 +++++--
 clang/test/Analysis/stream-errno.c            | 32 +++++++++++++++++++
 2 files changed, 41 insertions(+), 3 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
index 3b36565681a7f3..f934444eb4bf48 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
@@ -2859,13 +2859,19 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
         "fseeko",
         Signature(ArgTypes{FilePtrTy, Off_tTy, IntTy}, RetType{IntTy}),
         Summary(NoEvalCall)
-            .Case(ReturnsZeroOrMinusOne, ErrnoIrrelevant)
-            .ArgConstraint(NotNull(ArgNo(0))));
+            .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
+            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
+            .ArgConstraint(NotNull(ArgNo(0)))
+            .ArgConstraint(ArgumentCondition(2, WithinRange, {{0, 2}})));
 
     // off_t ftello(FILE *stream);
     addToFunctionSummaryMap(
         "ftello", Signature(ArgTypes{FilePtrTy}, RetType{Off_tTy}),
-        Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
+        Summary(NoEvalCall)
+            .Case({ReturnValueCondition(WithinRange, Range(0, LongMax))},
+                  ErrnoUnchanged, GenericSuccessMsg)
+            .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
+            .ArgConstraint(NotNull(ArgNo(0))));
 
     // void *mmap(void *addr, size_t length, int prot, int flags, int fd,
     // off_t offset);
diff --git a/clang/test/Analysis/stream-errno.c b/clang/test/Analysis/stream-errno.c
index f44ee6070708b2..bc184d5ce018d3 100644
--- a/clang/test/Analysis/stream-errno.c
+++ b/clang/test/Analysis/stream-errno.c
@@ -129,6 +129,7 @@ void check_fseek(void) {
   int S = fseek(F, 11, SEEK_SET);
   if (S != 0) {
     clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}}
+    clang_analyzer_eval(S == -1);    // expected-warning{{TRUE}}
     if (errno) {} // no-warning
     fclose(F);
     return;
@@ -136,6 +137,21 @@ void check_fseek(void) {
   if (errno) {} // expected-warning{{An undefined value may be read from 'errno'}}
 }
 
+void check_fseeko(void) {
+  FILE *F = tmpfile();
+  if (!F)
+    return;
+  int S = fseeko(F, 11, SEEK_SET);
+  if (S == -1) {
+    clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}}
+    if (errno) {}                    // no-warning
+  } else {
+    clang_analyzer_eval(S == 0);     // expected-warning{{TRUE}}
+    if (errno) {}                    // expected-warning{{An undefined value may be read from 'errno'}}
+  }
+  fclose(F);
+}
+
 void check_no_errno_change(void) {
   FILE *F = tmpfile();
   if (!F)
@@ -197,6 +213,22 @@ void check_ftell(void) {
   fclose(F);
 }
 
+void check_ftello(void) {
+  FILE *F = tmpfile();
+  if (!F)
+    return;
+  errno = 0;
+  off_t Ret = ftello(F);
+  if (Ret >= 0) {
+    clang_analyzer_eval(errno == 0); // expected-warning{{TRUE}}
+  } else {
+    clang_analyzer_eval(Ret == -1);  // expected-warning{{TRUE}}
+    clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}}
+  }
+  if (errno) {}                      // no-warning
+  fclose(F);
+}
+
 void check_rewind(void) {
   FILE *F = tmpfile();
   if (!F)



More information about the cfe-commits mailing list