diff options
author | Balázs Kéri <1.int32@gmail.com> | 2019-12-04 17:15:03 +0100 |
---|---|---|
committer | Balázs Kéri <1.int32@gmail.com> | 2019-12-05 11:08:44 +0100 |
commit | 7eafde981c699efa87c96d4b7714cbfe98c3d1c6 (patch) | |
tree | 68d136901d969809b3e793b348f0f8833540eb06 /clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp | |
parent | 4d6c4cb4269e8e8e04854fca812c2dda13f83f9d (diff) | |
download | bcm5719-llvm-7eafde981c699efa87c96d4b7714cbfe98c3d1c6.tar.gz bcm5719-llvm-7eafde981c699efa87c96d4b7714cbfe98c3d1c6.zip |
[Checkers] Added support for freopen to StreamChecker.
Summary: Extend StreamChecker with a new evaluation function for API call 'freopen'.
Reviewers: NoQ, baloghadamsoftware, Szelethus, martong
Reviewed By: baloghadamsoftware, martong
Subscribers: martong, rnkovacs, dkrupp, Szelethus, gamesh411, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69948
Diffstat (limited to 'clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp')
-rw-r--r-- | clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp index 7a0dda56328..47099f2afb6 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp @@ -64,6 +64,7 @@ private: CallDescriptionMap<FnCheck> Callbacks = { {{"fopen"}, &StreamChecker::evalFopen}, + {{"freopen", 3}, &StreamChecker::evalFreopen}, {{"tmpfile"}, &StreamChecker::evalFopen}, {{"fclose", 1}, &StreamChecker::evalFclose}, {{"fread", 4}, @@ -90,6 +91,7 @@ private: }; void evalFopen(const CallEvent &Call, CheckerContext &C) const; + void evalFreopen(const CallEvent &Call, CheckerContext &C) const; void evalFclose(const CallEvent &Call, CheckerContext &C) const; void evalFseek(const CallEvent &Call, CheckerContext &C) const; @@ -160,6 +162,49 @@ void StreamChecker::evalFopen(const CallEvent &Call, CheckerContext &C) const { C.addTransition(stateNull); } +void StreamChecker::evalFreopen(const CallEvent &Call, + CheckerContext &C) const { + ProgramStateRef State = C.getState(); + + auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr()); + if (!CE) + return; + + Optional<DefinedSVal> StreamVal = Call.getArgSVal(2).getAs<DefinedSVal>(); + if (!StreamVal) + return; + // Do not allow NULL as passed stream pointer. + // This is not specified in the man page but may crash on some system. + checkNullStream(*StreamVal, C, State); + // Check if error was generated. + if (C.isDifferent()) + return; + + SymbolRef StreamSym = StreamVal->getAsSymbol(); + // Do not care about special values for stream ("(FILE *)0x12345"?). + if (!StreamSym) + return; + + // Generate state for non-failed case. + // Return value is the passed stream pointer. + // According to the documentations, the stream is closed first + // but any close error is ignored. The state changes to (or remains) opened. + ProgramStateRef StateRetNotNull = + State->BindExpr(CE, C.getLocationContext(), *StreamVal); + // Generate state for NULL return value. + // Stream switches to OpenFailed state. + ProgramStateRef StateRetNull = State->BindExpr(CE, C.getLocationContext(), + C.getSValBuilder().makeNull()); + + StateRetNotNull = + StateRetNotNull->set<StreamMap>(StreamSym, StreamState::getOpened()); + StateRetNull = + StateRetNull->set<StreamMap>(StreamSym, StreamState::getOpenFailed()); + + C.addTransition(StateRetNotNull); + C.addTransition(StateRetNull); +} + void StreamChecker::evalFclose(const CallEvent &Call, CheckerContext &C) const { ProgramStateRef State = C.getState(); if (checkDoubleClose(Call, C, State)) |