Skip to content

Commit ff05c30

Browse files
authored
[clang][analyzer] Improve modeling of 'popen' and 'pclose' in StdLibraryFunctionsChecker (#78895)
1 parent c9790f8 commit ff05c30

File tree

4 files changed

+48
-17
lines changed

4 files changed

+48
-17
lines changed

clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2204,6 +2204,16 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
22042204
.ArgConstraint(NotNull(ArgNo(1)))
22052205
.ArgConstraint(NotNull(ArgNo(2))));
22062206

2207+
// FILE *popen(const char *command, const char *type);
2208+
addToFunctionSummaryMap(
2209+
"popen",
2210+
Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{FilePtrTy}),
2211+
Summary(NoEvalCall)
2212+
.Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
2213+
.Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2214+
.ArgConstraint(NotNull(ArgNo(0)))
2215+
.ArgConstraint(NotNull(ArgNo(1))));
2216+
22072217
// int fclose(FILE *stream);
22082218
addToFunctionSummaryMap(
22092219
"fclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
@@ -2212,6 +2222,15 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
22122222
.Case(ReturnsEOF, ErrnoNEZeroIrrelevant, GenericFailureMsg)
22132223
.ArgConstraint(NotNull(ArgNo(0))));
22142224

2225+
// int pclose(FILE *stream);
2226+
addToFunctionSummaryMap(
2227+
"pclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2228+
Summary(NoEvalCall)
2229+
.Case({ReturnValueCondition(WithinRange, {{0, IntMax}})},
2230+
ErrnoMustNotBeChecked, GenericSuccessMsg)
2231+
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2232+
.ArgConstraint(NotNull(ArgNo(0))));
2233+
22152234
// int ungetc(int c, FILE *stream);
22162235
addToFunctionSummaryMap(
22172236
"ungetc", Signature(ArgTypes{IntTy, FilePtrTy}, RetType{IntTy}),
@@ -2827,21 +2846,6 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
28272846
.ArgConstraint(
28282847
ArgumentCondition(0, WithinRange, Range(0, IntMax))));
28292848

2830-
// FILE *popen(const char *command, const char *type);
2831-
// FIXME: Improve for errno modeling.
2832-
addToFunctionSummaryMap(
2833-
"popen",
2834-
Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{FilePtrTy}),
2835-
Summary(NoEvalCall)
2836-
.ArgConstraint(NotNull(ArgNo(0)))
2837-
.ArgConstraint(NotNull(ArgNo(1))));
2838-
2839-
// int pclose(FILE *stream);
2840-
// FIXME: Improve for errno modeling.
2841-
addToFunctionSummaryMap(
2842-
"pclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2843-
Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2844-
28452849
// int close(int fildes);
28462850
addToFunctionSummaryMap(
28472851
"close", Signature(ArgTypes{IntTy}, RetType{IntTy}),

clang/test/Analysis/Inputs/system-header-simulator.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ FILE *fopen(const char *restrict path, const char *restrict mode);
4848
FILE *fdopen(int fd, const char *mode);
4949
FILE *tmpfile(void);
5050
FILE *freopen(const char *restrict pathname, const char *restrict mode, FILE *restrict stream);
51+
FILE *popen(const char *command, const char *mode);
5152
int fclose(FILE *fp);
53+
int pclose(FILE *stream);
5254
size_t fread(void *restrict, size_t, size_t, FILE *restrict);
5355
size_t fwrite(const void *restrict, size_t, size_t, FILE *restrict);
5456
int fgetc(FILE *stream);

clang/test/Analysis/errno-stdlibraryfunctions.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,28 @@ void errno_execvp(char *File, char * Argv[]) {
103103
clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}}
104104
if (errno) {} // no warning
105105
}
106+
107+
void errno_popen(void) {
108+
FILE *F = popen("xxx", "r");
109+
if (!F) {
110+
clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}}
111+
if (errno) {} // no-warning
112+
} else {
113+
if (errno) {} // expected-warning{{An undefined value may be read from 'errno' [unix.Errno]}}
114+
pclose(F);
115+
}
116+
}
117+
118+
void errno_pclose(void) {
119+
FILE *F = popen("xx", "w");
120+
if (!F)
121+
return;
122+
int Ret = pclose(F);
123+
if (Ret == -1) {
124+
clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}}
125+
if (errno) {} // no-warning
126+
} else {
127+
clang_analyzer_eval(Ret >= 0); // expected-warning{{TRUE}}
128+
if (errno) {} // expected-warning{{An undefined value may be read from 'errno'}}
129+
}
130+
}

clang/test/Analysis/std-c-library-functions-POSIX.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
// CHECK: Loaded summary for: FILE *fdopen(int fd, const char *mode)
2121
// CHECK: Loaded summary for: FILE *tmpfile(void)
2222
// CHECK: Loaded summary for: FILE *freopen(const char *restrict pathname, const char *restrict mode, FILE *restrict stream)
23+
// CHECK: Loaded summary for: FILE *popen(const char *command, const char *type)
2324
// CHECK: Loaded summary for: int fclose(FILE *stream)
25+
// CHECK: Loaded summary for: int pclose(FILE *stream)
2426
// CHECK: Loaded summary for: int fseek(FILE *stream, long offset, int whence)
2527
// CHECK: Loaded summary for: int fseeko(FILE *stream, off_t offset, int whence)
2628
// CHECK: Loaded summary for: off_t ftello(FILE *stream)
@@ -74,8 +76,6 @@
7476
// CHECK: Loaded summary for: DIR *opendir(const char *name)
7577
// CHECK: Loaded summary for: DIR *fdopendir(int fd)
7678
// CHECK: Loaded summary for: int isatty(int fildes)
77-
// CHECK: Loaded summary for: FILE *popen(const char *command, const char *type)
78-
// CHECK: Loaded summary for: int pclose(FILE *stream)
7979
// CHECK: Loaded summary for: int close(int fildes)
8080
// CHECK: Loaded summary for: long fpathconf(int fildes, int name)
8181
// CHECK: Loaded summary for: long pathconf(const char *path, int name)

0 commit comments

Comments
 (0)