Skip to content

[clang][analyzer] Improve modeling of 'popen' and 'pclose' in StdLibraryFunctionsChecker #78895

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 19 additions & 15 deletions clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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}),
Expand All @@ -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}),
Expand Down Expand Up @@ -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}),
Expand Down
2 changes: 2 additions & 0 deletions clang/test/Analysis/Inputs/system-header-simulator.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
25 changes: 25 additions & 0 deletions clang/test/Analysis/errno-stdlibraryfunctions.c
Original file line number Diff line number Diff line change
Expand Up @@ -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'}}
}
}
4 changes: 2 additions & 2 deletions clang/test/Analysis/std-c-library-functions-POSIX.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down