Skip to content

Commit be50ada

Browse files
authored
[clang][analyzer] Refine modeling of 'getcwd' in StdCLibraryFunctions checker (#141076)
Add extra branches for the case when the buffer argument is NULL. Fixes #135720
1 parent f1cf168 commit be50ada

File tree

2 files changed

+24
-5
lines changed

2 files changed

+24
-5
lines changed

clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2651,16 +2651,22 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
26512651
addToFunctionSummaryMap(
26522652
"getcwd", Signature(ArgTypes{CharPtrTy, SizeTy}, RetType{CharPtrTy}),
26532653
Summary(NoEvalCall)
2654-
.Case({ArgumentCondition(1, WithinRange, Range(1, SizeMax)),
2654+
.Case({NotNull(0),
2655+
ArgumentCondition(1, WithinRange, Range(1, SizeMax)),
26552656
ReturnValueCondition(BO_EQ, ArgNo(0))},
26562657
ErrnoMustNotBeChecked, GenericSuccessMsg)
2657-
.Case({ArgumentCondition(1, WithinRange, SingleValue(0)),
2658+
.Case({NotNull(0),
2659+
ArgumentCondition(1, WithinRange, SingleValue(0)),
26582660
IsNull(Ret)},
26592661
ErrnoNEZeroIrrelevant, "Assuming that argument 'size' is 0")
2660-
.Case({ArgumentCondition(1, WithinRange, Range(1, SizeMax)),
2662+
.Case({NotNull(0),
2663+
ArgumentCondition(1, WithinRange, Range(1, SizeMax)),
26612664
IsNull(Ret)},
26622665
ErrnoNEZeroIrrelevant, GenericFailureMsg)
2663-
.ArgConstraint(NotNull(ArgNo(0)))
2666+
.Case({IsNull(0), NotNull(Ret)}, ErrnoMustNotBeChecked,
2667+
GenericSuccessMsg)
2668+
.Case({IsNull(0), IsNull(Ret)}, ErrnoNEZeroIrrelevant,
2669+
GenericFailureMsg)
26642670
.ArgConstraint(
26652671
BufferSize(/*Buffer*/ ArgNo(0), /*BufSize*/ ArgNo(1)))
26662672
.ArgConstraint(

clang/test/Analysis/errno-stdlibraryfunctions.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,9 @@ void errno_mkdtemp3(CHAR_PTR template) {
9999
}
100100
}
101101

102-
void errno_getcwd(char *Buf, size_t Sz) {
102+
void errno_getcwd_buf_nonnull(char *Buf, size_t Sz) {
103+
if (Buf == NULL)
104+
return;
103105
char *Path = getcwd(Buf, Sz);
104106
if (Sz == 0) {
105107
clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}}
@@ -114,6 +116,17 @@ void errno_getcwd(char *Buf, size_t Sz) {
114116
}
115117
}
116118

119+
void errno_getcwd_buf_null() {
120+
// POSIX does not mention this case but many implementations (Linux, FreeBSD) work this way.
121+
char *Path = getcwd(NULL, 1);
122+
if (Path == NULL) {
123+
clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}}
124+
if (errno) {} // no warning
125+
} else {
126+
if (errno) {} // expected-warning{{An undefined value may be read from 'errno'}}
127+
}
128+
}
129+
117130
void errno_execv(char *Path, char * Argv[]) {
118131
int Ret = execv(Path, Argv);
119132
clang_analyzer_eval(Ret == -1); // expected-warning{{TRUE}}

0 commit comments

Comments
 (0)