Skip to content

Commit 27d963a

Browse files
authored
[clang][analyzer] Improve modeling of 'fseeko' and 'ftello' in StdLibraryFunctionsChecker (#77902)
1 parent f725bb9 commit 27d963a

File tree

3 files changed

+55
-17
lines changed

3 files changed

+55
-17
lines changed

clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2220,6 +2220,9 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
22202220
0, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}}))
22212221
.ArgConstraint(NotNull(ArgNo(1))));
22222222

2223+
std::optional<QualType> Off_tTy = lookupTy("off_t");
2224+
std::optional<RangeInt> Off_tMax = getMaxValue(Off_tTy);
2225+
22232226
// int fseek(FILE *stream, long offset, int whence);
22242227
// FIXME: It can be possible to get the 'SEEK_' values (like EOFv) and use
22252228
// these for condition of arg 2.
@@ -2232,6 +2235,16 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
22322235
.ArgConstraint(NotNull(ArgNo(0)))
22332236
.ArgConstraint(ArgumentCondition(2, WithinRange, {{0, 2}})));
22342237

2238+
// int fseeko(FILE *stream, off_t offset, int whence);
2239+
addToFunctionSummaryMap(
2240+
"fseeko",
2241+
Signature(ArgTypes{FilePtrTy, Off_tTy, IntTy}, RetType{IntTy}),
2242+
Summary(NoEvalCall)
2243+
.Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2244+
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2245+
.ArgConstraint(NotNull(ArgNo(0)))
2246+
.ArgConstraint(ArgumentCondition(2, WithinRange, {{0, 2}})));
2247+
22352248
// int fgetpos(FILE *restrict stream, fpos_t *restrict pos);
22362249
// From 'The Open Group Base Specifications Issue 7, 2018 edition':
22372250
// "The fgetpos() function shall not change the setting of errno if
@@ -2279,6 +2292,15 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
22792292
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
22802293
.ArgConstraint(NotNull(ArgNo(0))));
22812294

2295+
// off_t ftello(FILE *stream);
2296+
addToFunctionSummaryMap(
2297+
"ftello", Signature(ArgTypes{FilePtrTy}, RetType{Off_tTy}),
2298+
Summary(NoEvalCall)
2299+
.Case({ReturnValueCondition(WithinRange, Range(0, Off_tMax))},
2300+
ErrnoMustNotBeChecked, GenericSuccessMsg)
2301+
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2302+
.ArgConstraint(NotNull(ArgNo(0))));
2303+
22822304
// int fileno(FILE *stream);
22832305
addToFunctionSummaryMap(
22842306
"fileno", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
@@ -2410,8 +2432,6 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
24102432
.ArgConstraint(
24112433
ArgumentCondition(0, WithinRange, Range(0, IntMax))));
24122434

2413-
std::optional<QualType> Off_tTy = lookupTy("off_t");
2414-
24152435
// int truncate(const char *path, off_t length);
24162436
addToFunctionSummaryMap(
24172437
"truncate",
@@ -2854,19 +2874,6 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
28542874
"rand_r", Signature(ArgTypes{UnsignedIntPtrTy}, RetType{IntTy}),
28552875
Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
28562876

2857-
// int fseeko(FILE *stream, off_t offset, int whence);
2858-
addToFunctionSummaryMap(
2859-
"fseeko",
2860-
Signature(ArgTypes{FilePtrTy, Off_tTy, IntTy}, RetType{IntTy}),
2861-
Summary(NoEvalCall)
2862-
.Case(ReturnsZeroOrMinusOne, ErrnoIrrelevant)
2863-
.ArgConstraint(NotNull(ArgNo(0))));
2864-
2865-
// off_t ftello(FILE *stream);
2866-
addToFunctionSummaryMap(
2867-
"ftello", Signature(ArgTypes{FilePtrTy}, RetType{Off_tTy}),
2868-
Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2869-
28702877
// void *mmap(void *addr, size_t length, int prot, int flags, int fd,
28712878
// off_t offset);
28722879
// FIXME: Improve for errno modeling.

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
// CHECK: Loaded summary for: FILE *freopen(const char *restrict pathname, const char *restrict mode, FILE *restrict stream)
2222
// CHECK: Loaded summary for: int fclose(FILE *stream)
2323
// CHECK: Loaded summary for: int fseek(FILE *stream, long offset, int whence)
24+
// CHECK: Loaded summary for: int fseeko(FILE *stream, off_t offset, int whence)
25+
// CHECK: Loaded summary for: off_t ftello(FILE *stream)
2426
// CHECK: Loaded summary for: int fileno(FILE *stream)
2527
// CHECK: Loaded summary for: long a64l(const char *str64)
2628
// CHECK: Loaded summary for: char *l64a(long value)
@@ -80,8 +82,6 @@
8082
// CHECK: Loaded summary for: void rewinddir(DIR *dir)
8183
// CHECK: Loaded summary for: void seekdir(DIR *dirp, long loc)
8284
// CHECK: Loaded summary for: int rand_r(unsigned int *seedp)
83-
// CHECK: Loaded summary for: int fseeko(FILE *stream, off_t offset, int whence)
84-
// CHECK: Loaded summary for: off_t ftello(FILE *stream)
8585
// CHECK: Loaded summary for: void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
8686
// CHECK: Loaded summary for: void *mmap64(void *addr, size_t length, int prot, int flags, int fd, off64_t offset)
8787
// CHECK: Loaded summary for: int pipe(int fildes[2])

clang/test/Analysis/stream-errno.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,13 +129,29 @@ void check_fseek(void) {
129129
int S = fseek(F, 11, SEEK_SET);
130130
if (S != 0) {
131131
clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}}
132+
clang_analyzer_eval(S == -1); // expected-warning{{TRUE}}
132133
if (errno) {} // no-warning
133134
fclose(F);
134135
return;
135136
}
136137
if (errno) {} // expected-warning{{An undefined value may be read from 'errno'}}
137138
}
138139

140+
void check_fseeko(void) {
141+
FILE *F = tmpfile();
142+
if (!F)
143+
return;
144+
int S = fseeko(F, 11, SEEK_SET);
145+
if (S == -1) {
146+
clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}}
147+
if (errno) {} // no-warning
148+
} else {
149+
clang_analyzer_eval(S == 0); // expected-warning{{TRUE}}
150+
if (errno) {} // expected-warning{{An undefined value may be read from 'errno'}}
151+
}
152+
fclose(F);
153+
}
154+
139155
void check_no_errno_change(void) {
140156
FILE *F = tmpfile();
141157
if (!F)
@@ -197,6 +213,21 @@ void check_ftell(void) {
197213
fclose(F);
198214
}
199215

216+
void check_ftello(void) {
217+
FILE *F = tmpfile();
218+
if (!F)
219+
return;
220+
off_t Ret = ftello(F);
221+
if (Ret >= 0) {
222+
if (errno) {} // expected-warning{{An undefined value may be read from 'errno'}}
223+
} else {
224+
clang_analyzer_eval(Ret == -1); // expected-warning{{TRUE}}
225+
clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}}
226+
if (errno) {} // no-warning
227+
}
228+
fclose(F);
229+
}
230+
200231
void check_rewind(void) {
201232
FILE *F = tmpfile();
202233
if (!F)

0 commit comments

Comments
 (0)