[clang] [clang][analyzer] Implement modeling of 'fputc' in the StdLibraryFunctionsChecker (PR #77435)

Ben Shi via cfe-commits cfe-commits at lists.llvm.org
Tue Jan 9 01:50:08 PST 2024


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

None

>From 0ff61f497b99b45b1697289cf5d44fb3ecab2aba Mon Sep 17 00:00:00 2001
From: Ben Shi <bennshi at tencent.com>
Date: Tue, 9 Jan 2024 17:48:02 +0800
Subject: [PATCH] [clang][analyzer] Implement modeling of 'fputc' in the
 StdLibraryFunctionsChecker

---
 .../Checkers/StdLibraryFunctionsChecker.cpp        | 14 ++++++++++++++
 .../test/Analysis/Inputs/std-c-library-functions.h |  1 +
 clang/test/Analysis/errno-stdlibraryfunctions.c    | 14 ++++++++++++++
 3 files changed, 29 insertions(+)

diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
index 034825d88a44de..f160c464dc273a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
@@ -2277,6 +2277,20 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
                                 .Case({}, ErrnoMustBeChecked)
                                 .ArgConstraint(NotNull(ArgNo(0))));
 
+    // int fputc(int c, FILE *stream);
+    addToFunctionSummaryMap(
+        "fputc", Signature(ArgTypes{IntTy, FilePtrTy}, RetType{IntTy}),
+        Summary(NoEvalCall)
+            .Case({ArgumentCondition(0, WithinRange, Range(0, UCharRangeMax)),
+                   ReturnValueCondition(BO_EQ, ArgNo(0))},
+                  ErrnoMustNotBeChecked, GenericSuccessMsg)
+            .Case({ArgumentCondition(0, OutOfRange, Range(0, UCharRangeMax)),
+                   ReturnValueCondition(WithinRange, Range(0, UCharRangeMax))},
+                  ErrnoMustNotBeChecked, GenericSuccessMsg)
+            .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv))},
+                  ErrnoNEZeroIrrelevant, GenericFailureMsg)
+            .ArgConstraint(NotNull(ArgNo(1))));
+
     // void clearerr(FILE *stream);
     addToFunctionSummaryMap(
         "clearerr", Signature(ArgTypes{FilePtrTy}, RetType{VoidTy}),
diff --git a/clang/test/Analysis/Inputs/std-c-library-functions.h b/clang/test/Analysis/Inputs/std-c-library-functions.h
index 7c86c359ee21de..6cb2d1be7a9b11 100644
--- a/clang/test/Analysis/Inputs/std-c-library-functions.h
+++ b/clang/test/Analysis/Inputs/std-c-library-functions.h
@@ -37,6 +37,7 @@ int toascii(int);
 
 int getc(FILE *);
 int fgetc(FILE *);
+int fputc(int c, FILE *stream);
 int getchar(void);
 size_t fread(void *restrict, size_t, size_t, FILE *restrict);
 size_t fwrite(const void *restrict, size_t, size_t, FILE *restrict);
diff --git a/clang/test/Analysis/errno-stdlibraryfunctions.c b/clang/test/Analysis/errno-stdlibraryfunctions.c
index 9e3d07e7aa88a0..9ece662a937072 100644
--- a/clang/test/Analysis/errno-stdlibraryfunctions.c
+++ b/clang/test/Analysis/errno-stdlibraryfunctions.c
@@ -89,3 +89,17 @@ void errno_getcwd(char *Buf, size_t Sz) {
     if (errno) {}                      // expected-warning{{An undefined value may be read from 'errno'}}
   }
 }
+
+void errno_fputc(int C, FILE *Fp) {
+  int Ret = fputc(C, Fp);
+  if (Ret == EOF) {
+    clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}}
+    if (errno) {}                    // no warning
+  } else if (C >= 0 && C <= 255) {
+    clang_analyzer_eval(Ret == C);   // expected-warning{{TRUE}}
+    if (errno) {}                    // expected-warning{{An undefined value may be read from 'errno'}}
+  } else {
+    clang_analyzer_eval(Ret != C);   // expected-warning{{TRUE}}
+    if (errno) {}                    // expected-warning{{An undefined value may be read from 'errno'}}
+  }
+}



More information about the cfe-commits mailing list