Skip to content

Commit

Permalink
[clang][analyzer] Improve modeling of 'popen' and 'pclose' in StdLibr…
Browse files Browse the repository at this point in the history
…aryFunctionsChecker (llvm#78895)
  • Loading branch information
benshi001 authored Jan 27, 2024
1 parent c9790f8 commit ff05c30
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 17 deletions.
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

0 comments on commit ff05c30

Please sign in to comment.