[clang] Improve modeling of 'opendir' and 'fdopendir' in StdLibraryFunctionsChecker (PR #78079)

Ben Shi via cfe-commits cfe-commits at lists.llvm.org
Sat Jan 13 20:53:54 PST 2024


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

None

>From 2b3d2800be52fb28246c2b51fad7eafc106e3e20 Mon Sep 17 00:00:00 2001
From: Ben Shi <bennshi at tencent.com>
Date: Sun, 14 Jan 2024 12:44:45 +0800
Subject: [PATCH] Improve modeling of 'opendir' and 'fdopendir' in
 StdLibraryFunctionsChecker

---
 .../Checkers/StdLibraryFunctionsChecker.cpp   | 19 +++++++++-------
 .../Analysis/Inputs/system-header-simulator.h |  7 +++++-
 clang/test/Analysis/stream-errno.c            | 22 +++++++++++++++++++
 3 files changed, 39 insertions(+), 9 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
index 3b36565681a7f3..2f05dd6997cfad 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
@@ -2772,18 +2772,21 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
             .ArgConstraint(NotNull(ArgNo(2))));
 
     // DIR *opendir(const char *name);
-    // FIXME: Improve for errno modeling.
     addToFunctionSummaryMap(
         "opendir", Signature(ArgTypes{ConstCharPtrTy}, RetType{DirPtrTy}),
-        Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
+        Summary(NoEvalCall)
+            .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
+            .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
+            .ArgConstraint(NotNull(ArgNo(0))));
 
     // DIR *fdopendir(int fd);
-    // FIXME: Improve for errno modeling.
-    addToFunctionSummaryMap("fdopendir",
-                            Signature(ArgTypes{IntTy}, RetType{DirPtrTy}),
-                            Summary(NoEvalCall)
-                                .ArgConstraint(ArgumentCondition(
-                                    0, WithinRange, Range(0, IntMax))));
+    addToFunctionSummaryMap(
+        "fdopendir", Signature(ArgTypes{IntTy}, RetType{DirPtrTy}),
+        Summary(NoEvalCall)
+            .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
+            .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
+            .ArgConstraint(
+                ArgumentCondition(0, WithinRange, Range(0, IntMax))));
 
     // int isatty(int fildes);
     addToFunctionSummaryMap(
diff --git a/clang/test/Analysis/Inputs/system-header-simulator.h b/clang/test/Analysis/Inputs/system-header-simulator.h
index cd7ac616bcc67f..ba0e09ca77bc2a 100644
--- a/clang/test/Analysis/Inputs/system-header-simulator.h
+++ b/clang/test/Analysis/Inputs/system-header-simulator.h
@@ -14,8 +14,9 @@ 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;
+typedef struct _DIR DIR;
+
 #define SEEK_SET 0 /* Seek from beginning of file. */
 #define SEEK_CUR 1 /* Seek from current position. */
 #define SEEK_END 2 /* Seek from end of file. */
@@ -68,6 +69,10 @@ int ferror(FILE *stream);
 int fileno(FILE *stream);
 int fflush(FILE *stream);
 
+DIR *opendir(const char *name);
+DIR *fdopendir(int fd);
+int closedir(DIR *dir);
+
 size_t strlen(const char *);
 
 char *strcpy(char *restrict, const char *restrict);
diff --git a/clang/test/Analysis/stream-errno.c b/clang/test/Analysis/stream-errno.c
index f44ee6070708b2..f19109a3c0b481 100644
--- a/clang/test/Analysis/stream-errno.c
+++ b/clang/test/Analysis/stream-errno.c
@@ -248,3 +248,25 @@ void check_fflush_all(void) {
     if (errno) {}                    // no-warning
   }
 }
+
+void check_opendir(const char *Path) {
+  DIR *Dir = opendir(Path);
+  if (Dir == NULL) {
+    clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}}
+    if (errno) {}                    // no-warning
+  } else {
+    if (errno) {}                    // expected-warning{{An undefined value may be read from 'errno'}}
+    closedir(Dir);
+  }
+}
+
+void check_fdopendir(int Fd) {
+  DIR *Dir = fdopendir(Fd);
+  if (Dir == NULL) {
+    clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}}
+    if (errno) {}                    // no-warning
+  } else {
+    if (errno) {}                    // expected-warning{{An undefined value may be read from 'errno'}}
+    closedir(Dir);
+  }
+}



More information about the cfe-commits mailing list