[clang] [clang][analyzer] Improve modeling of 'popen' and 'pclose' in StdLibraryFunctionsChecker (PR #78895)
Ben Shi via cfe-commits
cfe-commits at lists.llvm.org
Wed Jan 24 21:05:00 PST 2024
https://github.com/benshi001 updated https://github.com/llvm/llvm-project/pull/78895
>From 382ae9d692df575f47c203c9fff2036c42c4833b Mon Sep 17 00:00:00 2001
From: Ben Shi <bennshi at tencent.com>
Date: Sun, 21 Jan 2024 18:29:06 +0800
Subject: [PATCH 1/2] [clang][analyzer] Improve modeling of 'popen' and
'pclose' in StdLibraryFunctionsChecker
---
.../Checkers/StdLibraryFunctionsChecker.cpp | 34 +++++++++++--------
.../Analysis/Inputs/system-header-simulator.h | 2 ++
.../Analysis/std-c-library-functions-POSIX.c | 4 +--
clang/test/Analysis/stream-errno.c | 25 ++++++++++++++
4 files changed, 48 insertions(+), 17 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
index 61bf3c8528be2b..be26f5521c8d76 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
@@ -2204,6 +2204,16 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.ArgConstraint(NotNull(ArgNo(1)))
.ArgConstraint(NotNull(ArgNo(2))));
+ // FILE *popen(const char *command, const char *type);
+ addToFunctionSummaryMap(
+ "popen",
+ Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{FilePtrTy}),
+ Summary(NoEvalCall)
+ .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
+ .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
+ .ArgConstraint(NotNull(ArgNo(0)))
+ .ArgConstraint(NotNull(ArgNo(1))));
+
// int fclose(FILE *stream);
addToFunctionSummaryMap(
"fclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
@@ -2212,6 +2222,15 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.Case(ReturnsEOF, ErrnoNEZeroIrrelevant, GenericFailureMsg)
.ArgConstraint(NotNull(ArgNo(0))));
+ // int pclose(FILE *stream);
+ addToFunctionSummaryMap(
+ "pclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
+ Summary(NoEvalCall)
+ .Case({ReturnValueCondition(WithinRange, {{0, IntMax}})},
+ ErrnoMustNotBeChecked, GenericSuccessMsg)
+ .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
+ .ArgConstraint(NotNull(ArgNo(0))));
+
// int ungetc(int c, FILE *stream);
addToFunctionSummaryMap(
"ungetc", Signature(ArgTypes{IntTy, FilePtrTy}, RetType{IntTy}),
@@ -2827,21 +2846,6 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.ArgConstraint(
ArgumentCondition(0, WithinRange, Range(0, IntMax))));
- // FILE *popen(const char *command, const char *type);
- // FIXME: Improve for errno modeling.
- addToFunctionSummaryMap(
- "popen",
- Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{FilePtrTy}),
- Summary(NoEvalCall)
- .ArgConstraint(NotNull(ArgNo(0)))
- .ArgConstraint(NotNull(ArgNo(1))));
-
- // int pclose(FILE *stream);
- // FIXME: Improve for errno modeling.
- addToFunctionSummaryMap(
- "pclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
- Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
-
// int close(int fildes);
addToFunctionSummaryMap(
"close", Signature(ArgTypes{IntTy}, RetType{IntTy}),
diff --git a/clang/test/Analysis/Inputs/system-header-simulator.h b/clang/test/Analysis/Inputs/system-header-simulator.h
index 96072741a8abc1..15986984802c0e 100644
--- a/clang/test/Analysis/Inputs/system-header-simulator.h
+++ b/clang/test/Analysis/Inputs/system-header-simulator.h
@@ -48,7 +48,9 @@ FILE *fopen(const char *restrict path, const char *restrict mode);
FILE *fdopen(int fd, const char *mode);
FILE *tmpfile(void);
FILE *freopen(const char *restrict pathname, const char *restrict mode, FILE *restrict stream);
+FILE *popen(const char *command, const char *mode);
int fclose(FILE *fp);
+int pclose(FILE *stream);
size_t fread(void *restrict, size_t, size_t, FILE *restrict);
size_t fwrite(const void *restrict, size_t, size_t, FILE *restrict);
int fgetc(FILE *stream);
diff --git a/clang/test/Analysis/std-c-library-functions-POSIX.c b/clang/test/Analysis/std-c-library-functions-POSIX.c
index 51b136d9ba3567..03aa8e2e00a75d 100644
--- a/clang/test/Analysis/std-c-library-functions-POSIX.c
+++ b/clang/test/Analysis/std-c-library-functions-POSIX.c
@@ -20,7 +20,9 @@
// CHECK: Loaded summary for: FILE *fdopen(int fd, const char *mode)
// CHECK: Loaded summary for: FILE *tmpfile(void)
// CHECK: Loaded summary for: FILE *freopen(const char *restrict pathname, const char *restrict mode, FILE *restrict stream)
+// CHECK: Loaded summary for: FILE *popen(const char *command, const char *type)
// CHECK: Loaded summary for: int fclose(FILE *stream)
+// CHECK: Loaded summary for: int pclose(FILE *stream)
// CHECK: Loaded summary for: int fseek(FILE *stream, long offset, int whence)
// CHECK: Loaded summary for: int fseeko(FILE *stream, off_t offset, int whence)
// CHECK: Loaded summary for: off_t ftello(FILE *stream)
@@ -74,8 +76,6 @@
// CHECK: Loaded summary for: DIR *opendir(const char *name)
// CHECK: Loaded summary for: DIR *fdopendir(int fd)
// CHECK: Loaded summary for: int isatty(int fildes)
-// CHECK: Loaded summary for: FILE *popen(const char *command, const char *type)
-// CHECK: Loaded summary for: int pclose(FILE *stream)
// CHECK: Loaded summary for: int close(int fildes)
// CHECK: Loaded summary for: long fpathconf(int fildes, int name)
// CHECK: Loaded summary for: long pathconf(const char *path, int name)
diff --git a/clang/test/Analysis/stream-errno.c b/clang/test/Analysis/stream-errno.c
index fab6a58b3275a8..44bf949673082d 100644
--- a/clang/test/Analysis/stream-errno.c
+++ b/clang/test/Analysis/stream-errno.c
@@ -51,6 +51,17 @@ void check_freopen(void) {
if (errno) {} // expected-warning{{An undefined value may be read from 'errno'}}
}
+void check_popen(void) {
+ FILE *F = popen("xxx", "r");
+ if (!F) {
+ 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' [unix.Errno]}}
+ pclose(F);
+ }
+}
+
void check_fclose(void) {
FILE *F = tmpfile();
if (!F)
@@ -64,6 +75,20 @@ void check_fclose(void) {
if (errno) {} // expected-warning{{An undefined value may be read from 'errno'}}
}
+void check_pclose(void) {
+ FILE *F = popen("xx", "w");
+ if (!F)
+ return;
+ int Ret = pclose(F);
+ if (Ret == -1) {
+ clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}}
+ if (errno) {} // no-warning
+ } else {
+ clang_analyzer_eval(Ret >= 0); // expected-warning{{TRUE}}
+ if (errno) {} // expected-warning{{An undefined value may be read from 'errno'}}
+ }
+}
+
void check_fread_size0(void) {
char Buf[10];
FILE *F = tmpfile();
>From 8a57c1a2037e7ae31eb561318156a9231d899812 Mon Sep 17 00:00:00 2001
From: Ben Shi <bennshi at tencent.com>
Date: Thu, 25 Jan 2024 12:55:50 +0800
Subject: [PATCH 2/2] [clang][analyzer] Improve modeling of 'popen' and
'pclose' in StdLibraryFunctionsChecker
---
.../test/Analysis/errno-stdlibraryfunctions.c | 25 +++++++++++++++++++
clang/test/Analysis/stream-errno.c | 25 -------------------
2 files changed, 25 insertions(+), 25 deletions(-)
diff --git a/clang/test/Analysis/errno-stdlibraryfunctions.c b/clang/test/Analysis/errno-stdlibraryfunctions.c
index 7876bafc2eb210..9b487fed0a2eb8 100644
--- a/clang/test/Analysis/errno-stdlibraryfunctions.c
+++ b/clang/test/Analysis/errno-stdlibraryfunctions.c
@@ -103,3 +103,28 @@ void errno_execvp(char *File, char * Argv[]) {
clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}}
if (errno) {} // no warning
}
+
+void errno_popen(void) {
+ FILE *F = popen("xxx", "r");
+ if (!F) {
+ 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' [unix.Errno]}}
+ pclose(F);
+ }
+}
+
+void errno_pclose(void) {
+ FILE *F = popen("xx", "w");
+ if (!F)
+ return;
+ int Ret = pclose(F);
+ if (Ret == -1) {
+ clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}}
+ if (errno) {} // no-warning
+ } else {
+ clang_analyzer_eval(Ret >= 0); // expected-warning{{TRUE}}
+ if (errno) {} // expected-warning{{An undefined value may be read from 'errno'}}
+ }
+}
diff --git a/clang/test/Analysis/stream-errno.c b/clang/test/Analysis/stream-errno.c
index 44bf949673082d..fab6a58b3275a8 100644
--- a/clang/test/Analysis/stream-errno.c
+++ b/clang/test/Analysis/stream-errno.c
@@ -51,17 +51,6 @@ void check_freopen(void) {
if (errno) {} // expected-warning{{An undefined value may be read from 'errno'}}
}
-void check_popen(void) {
- FILE *F = popen("xxx", "r");
- if (!F) {
- 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' [unix.Errno]}}
- pclose(F);
- }
-}
-
void check_fclose(void) {
FILE *F = tmpfile();
if (!F)
@@ -75,20 +64,6 @@ void check_fclose(void) {
if (errno) {} // expected-warning{{An undefined value may be read from 'errno'}}
}
-void check_pclose(void) {
- FILE *F = popen("xx", "w");
- if (!F)
- return;
- int Ret = pclose(F);
- if (Ret == -1) {
- clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}}
- if (errno) {} // no-warning
- } else {
- clang_analyzer_eval(Ret >= 0); // expected-warning{{TRUE}}
- if (errno) {} // expected-warning{{An undefined value may be read from 'errno'}}
- }
-}
-
void check_fread_size0(void) {
char Buf[10];
FILE *F = tmpfile();
More information about the cfe-commits
mailing list