diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp index fbfa101257d5e..742426a628e06 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp @@ -268,8 +268,12 @@ class StreamChecker : public Checker(); ProgramStateRef StateNotFailed = State->BindExpr(CE, C.getLocationContext(), RetVal); - auto Cond = SVB.evalBinOp(State, BO_GE, RetVal, - SVB.makeZeroVal(C.getASTContext().LongTy), - SVB.getConditionType()) - .getAs(); + auto Cond = + SVB.evalBinOp(State, BO_GE, RetVal, SVB.makeZeroVal(Call.getResultType()), + SVB.getConditionType()) + .getAs(); if (!Cond) return; StateNotFailed = StateNotFailed->assume(*Cond, true); @@ -1124,7 +1128,7 @@ void StreamChecker::evalFtell(const FnDescription *Desc, const CallEvent &Call, return; ProgramStateRef StateFailed = State->BindExpr( - CE, C.getLocationContext(), SVB.makeIntVal(-1, C.getASTContext().LongTy)); + CE, C.getLocationContext(), SVB.makeIntVal(-1, Call.getResultType())); // This function does not affect the stream state. // Still we add success and failure state with the appropriate return value. diff --git a/clang/test/Analysis/Inputs/system-header-simulator.h b/clang/test/Analysis/Inputs/system-header-simulator.h index caae59c38a4c8..cd7ac616bcc67 100644 --- a/clang/test/Analysis/Inputs/system-header-simulator.h +++ b/clang/test/Analysis/Inputs/system-header-simulator.h @@ -13,6 +13,7 @@ typedef __typeof(sizeof(int)) size_t; typedef long long __int64_t; typedef __int64_t __darwin_off_t; typedef __darwin_off_t fpos_t; +typedef int off_t; typedef struct _FILE FILE; #define SEEK_SET 0 /* Seek from beginning of file. */ @@ -55,7 +56,9 @@ int fputc(int ch, FILE *stream); int fputs(const char *restrict s, FILE *restrict stream); int ungetc(int c, FILE *stream); int fseek(FILE *__stream, long int __off, int __whence); +int fseeko(FILE *__stream, off_t __off, int __whence); long int ftell(FILE *__stream); +off_t ftello(FILE *__stream); void rewind(FILE *__stream); int fgetpos(FILE *restrict stream, fpos_t *restrict pos); int fsetpos(FILE *stream, const fpos_t *pos); diff --git a/clang/test/Analysis/stream-error.c b/clang/test/Analysis/stream-error.c index c038348e799d2..2d03c0bbe7c47 100644 --- a/clang/test/Analysis/stream-error.c +++ b/clang/test/Analysis/stream-error.c @@ -295,6 +295,25 @@ void error_fseek(void) { fclose(F); } +void error_fseeko(void) { + FILE *F = fopen("file", "r"); + if (!F) + return; + int rc = fseeko(F, 1, SEEK_SET); + if (rc) { + int IsFEof = feof(F), IsFError = ferror(F); + // Get feof or ferror or no error. + clang_analyzer_eval(IsFEof || IsFError); + // expected-warning@-1 {{FALSE}} + // expected-warning@-2 {{TRUE}} + clang_analyzer_eval(IsFEof && IsFError); // expected-warning {{FALSE}} + } else { + clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}} + clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}} + } + fclose(F); +} + void error_fseek_0(void) { FILE *F = fopen("file", "r"); if (!F) @@ -324,6 +343,68 @@ void error_fseek_0(void) { fclose(F); } +void error_fseeko_0(void) { + FILE *F = fopen("file", "r"); + if (!F) + return; + int rc = fseeko(F, 0, SEEK_SET); + if (rc) { + int IsFEof = feof(F), IsFError = ferror(F); + // Get ferror or no error, but not feof. + clang_analyzer_eval(IsFError); + // expected-warning@-1 {{FALSE}} + // expected-warning@-2 {{TRUE}} + clang_analyzer_eval(IsFEof); + // expected-warning@-1 {{FALSE}} + } else { + clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}} + clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}} + } + fclose(F); +} + +void error_ftell(void) { + FILE *F = fopen("file", "r"); + if (!F) + return; + long rc = ftell(F); + if (rc >= 0) + clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}} + else + clang_analyzer_eval(rc == -1); // expected-warning {{TRUE}} + clang_analyzer_eval(feof(F) && ferror(F)); // expected-warning {{FALSE}} + StreamTesterChecker_make_feof_stream(F); + rc = ftell(F); + clang_analyzer_eval(feof(F)); // expected-warning {{TRUE}} + clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}} + StreamTesterChecker_make_ferror_stream(F); + rc = ftell(F); + clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}} + clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}} + fclose(F); +} + +void error_ftello(void) { + FILE *F = fopen("file", "r"); + if (!F) + return; + off_t rc = ftello(F); + if (rc >= 0) + clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}} + else + clang_analyzer_eval(rc == -1); // expected-warning {{TRUE}} + clang_analyzer_eval(feof(F) && ferror(F)); // expected-warning {{FALSE}} + StreamTesterChecker_make_feof_stream(F); + rc = ftello(F); + clang_analyzer_eval(feof(F)); // expected-warning {{TRUE}} + clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}} + StreamTesterChecker_make_ferror_stream(F); + rc = ftello(F); + clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}} + clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}} + fclose(F); +} + void error_fflush_after_fclose(void) { FILE *F = tmpfile(); int Ret;