Skip to content

Commit 19081f4

Browse files
authored
[clang][analyzer] Support 'tello' and 'fseeko' in the StreamChecker (llvm#77580)
1 parent 9ca6e5b commit 19081f4

File tree

3 files changed

+93
-5
lines changed

3 files changed

+93
-5
lines changed

clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -268,8 +268,12 @@ class StreamChecker : public Checker<check::PreCall, eval::Call,
268268
std::bind(&StreamChecker::evalUngetc, _1, _2, _3, _4), 1}},
269269
{{{"fseek"}, 3},
270270
{&StreamChecker::preFseek, &StreamChecker::evalFseek, 0}},
271+
{{{"fseeko"}, 3},
272+
{&StreamChecker::preFseek, &StreamChecker::evalFseek, 0}},
271273
{{{"ftell"}, 1},
272274
{&StreamChecker::preDefault, &StreamChecker::evalFtell, 0}},
275+
{{{"ftello"}, 1},
276+
{&StreamChecker::preDefault, &StreamChecker::evalFtell, 0}},
273277
{{{"fflush"}, 1},
274278
{&StreamChecker::preFflush, &StreamChecker::evalFflush, 0}},
275279
{{{"rewind"}, 1},
@@ -1113,18 +1117,18 @@ void StreamChecker::evalFtell(const FnDescription *Desc, const CallEvent &Call,
11131117
NonLoc RetVal = makeRetVal(C, CE).castAs<NonLoc>();
11141118
ProgramStateRef StateNotFailed =
11151119
State->BindExpr(CE, C.getLocationContext(), RetVal);
1116-
auto Cond = SVB.evalBinOp(State, BO_GE, RetVal,
1117-
SVB.makeZeroVal(C.getASTContext().LongTy),
1118-
SVB.getConditionType())
1119-
.getAs<DefinedOrUnknownSVal>();
1120+
auto Cond =
1121+
SVB.evalBinOp(State, BO_GE, RetVal, SVB.makeZeroVal(Call.getResultType()),
1122+
SVB.getConditionType())
1123+
.getAs<DefinedOrUnknownSVal>();
11201124
if (!Cond)
11211125
return;
11221126
StateNotFailed = StateNotFailed->assume(*Cond, true);
11231127
if (!StateNotFailed)
11241128
return;
11251129

11261130
ProgramStateRef StateFailed = State->BindExpr(
1127-
CE, C.getLocationContext(), SVB.makeIntVal(-1, C.getASTContext().LongTy));
1131+
CE, C.getLocationContext(), SVB.makeIntVal(-1, Call.getResultType()));
11281132

11291133
// This function does not affect the stream state.
11301134
// Still we add success and failure state with the appropriate return value.

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ typedef __typeof(sizeof(int)) size_t;
1313
typedef long long __int64_t;
1414
typedef __int64_t __darwin_off_t;
1515
typedef __darwin_off_t fpos_t;
16+
typedef int off_t;
1617

1718
typedef struct _FILE FILE;
1819
#define SEEK_SET 0 /* Seek from beginning of file. */
@@ -55,7 +56,9 @@ int fputc(int ch, FILE *stream);
5556
int fputs(const char *restrict s, FILE *restrict stream);
5657
int ungetc(int c, FILE *stream);
5758
int fseek(FILE *__stream, long int __off, int __whence);
59+
int fseeko(FILE *__stream, off_t __off, int __whence);
5860
long int ftell(FILE *__stream);
61+
off_t ftello(FILE *__stream);
5962
void rewind(FILE *__stream);
6063
int fgetpos(FILE *restrict stream, fpos_t *restrict pos);
6164
int fsetpos(FILE *stream, const fpos_t *pos);

clang/test/Analysis/stream-error.c

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,25 @@ void error_fseek(void) {
295295
fclose(F);
296296
}
297297

298+
void error_fseeko(void) {
299+
FILE *F = fopen("file", "r");
300+
if (!F)
301+
return;
302+
int rc = fseeko(F, 1, SEEK_SET);
303+
if (rc) {
304+
int IsFEof = feof(F), IsFError = ferror(F);
305+
// Get feof or ferror or no error.
306+
clang_analyzer_eval(IsFEof || IsFError);
307+
// expected-warning@-1 {{FALSE}}
308+
// expected-warning@-2 {{TRUE}}
309+
clang_analyzer_eval(IsFEof && IsFError); // expected-warning {{FALSE}}
310+
} else {
311+
clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}}
312+
clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
313+
}
314+
fclose(F);
315+
}
316+
298317
void error_fseek_0(void) {
299318
FILE *F = fopen("file", "r");
300319
if (!F)
@@ -324,6 +343,68 @@ void error_fseek_0(void) {
324343
fclose(F);
325344
}
326345

346+
void error_fseeko_0(void) {
347+
FILE *F = fopen("file", "r");
348+
if (!F)
349+
return;
350+
int rc = fseeko(F, 0, SEEK_SET);
351+
if (rc) {
352+
int IsFEof = feof(F), IsFError = ferror(F);
353+
// Get ferror or no error, but not feof.
354+
clang_analyzer_eval(IsFError);
355+
// expected-warning@-1 {{FALSE}}
356+
// expected-warning@-2 {{TRUE}}
357+
clang_analyzer_eval(IsFEof);
358+
// expected-warning@-1 {{FALSE}}
359+
} else {
360+
clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}}
361+
clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
362+
}
363+
fclose(F);
364+
}
365+
366+
void error_ftell(void) {
367+
FILE *F = fopen("file", "r");
368+
if (!F)
369+
return;
370+
long rc = ftell(F);
371+
if (rc >= 0)
372+
clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
373+
else
374+
clang_analyzer_eval(rc == -1); // expected-warning {{TRUE}}
375+
clang_analyzer_eval(feof(F) && ferror(F)); // expected-warning {{FALSE}}
376+
StreamTesterChecker_make_feof_stream(F);
377+
rc = ftell(F);
378+
clang_analyzer_eval(feof(F)); // expected-warning {{TRUE}}
379+
clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
380+
StreamTesterChecker_make_ferror_stream(F);
381+
rc = ftell(F);
382+
clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}}
383+
clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}}
384+
fclose(F);
385+
}
386+
387+
void error_ftello(void) {
388+
FILE *F = fopen("file", "r");
389+
if (!F)
390+
return;
391+
off_t rc = ftello(F);
392+
if (rc >= 0)
393+
clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
394+
else
395+
clang_analyzer_eval(rc == -1); // expected-warning {{TRUE}}
396+
clang_analyzer_eval(feof(F) && ferror(F)); // expected-warning {{FALSE}}
397+
StreamTesterChecker_make_feof_stream(F);
398+
rc = ftello(F);
399+
clang_analyzer_eval(feof(F)); // expected-warning {{TRUE}}
400+
clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
401+
StreamTesterChecker_make_ferror_stream(F);
402+
rc = ftello(F);
403+
clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}}
404+
clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}}
405+
fclose(F);
406+
}
407+
327408
void error_fflush_after_fclose(void) {
328409
FILE *F = tmpfile();
329410
int Ret;

0 commit comments

Comments
 (0)