diff options
author | dim <dim@FreeBSD.org> | 2013-04-08 18:45:10 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2013-04-08 18:45:10 +0000 |
commit | c72c57c9e9b69944e3e009cd5e209634839581d3 (patch) | |
tree | 4fc2f184c499d106f29a386c452b49e5197bf63d /lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp | |
parent | 5b20025c30d23d521e12c1f33ec8fa6b821952cd (diff) | |
download | FreeBSD-src-c72c57c9e9b69944e3e009cd5e209634839581d3.zip FreeBSD-src-c72c57c9e9b69944e3e009cd5e209634839581d3.tar.gz |
Vendor import of clang trunk r178860:
http://llvm.org/svn/llvm-project/cfe/trunk@178860
Diffstat (limited to 'lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp | 98 |
1 files changed, 67 insertions, 31 deletions
diff --git a/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp b/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp index 37ec1aa..7a5d993 100644 --- a/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp @@ -14,19 +14,23 @@ //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" -#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" using namespace clang; using namespace ento; namespace { -class ReturnUndefChecker : - public Checker< check::PreStmt<ReturnStmt> > { - mutable OwningPtr<BuiltinBug> BT; +class ReturnUndefChecker : public Checker< check::PreStmt<ReturnStmt> > { + mutable OwningPtr<BuiltinBug> BT_Undef; + mutable OwningPtr<BuiltinBug> BT_NullReference; + + void emitUndef(CheckerContext &C, const Expr *RetE) const; + void checkReference(CheckerContext &C, const Expr *RetE, + DefinedOrUnknownSVal RetVal) const; public: void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const; }; @@ -34,43 +38,75 @@ public: void ReturnUndefChecker::checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const { - const Expr *RetE = RS->getRetValue(); if (!RetE) return; - - if (!C.getState()->getSVal(RetE, C.getLocationContext()).isUndef()) - return; - - // "return;" is modeled to evaluate to an UndefinedValue. Allow UndefinedValue - // to be returned in functions returning void to support the following pattern: - // void foo() { - // return; - // } - // void test() { - // return foo(); - // } + SVal RetVal = C.getSVal(RetE); + const StackFrameContext *SFC = C.getStackFrame(); QualType RT = CallEvent::getDeclaredResultType(SFC->getDecl()); - if (!RT.isNull() && RT->isSpecificBuiltinType(BuiltinType::Void)) + + if (RetVal.isUndef()) { + // "return;" is modeled to evaluate to an UndefinedVal. Allow UndefinedVal + // to be returned in functions returning void to support this pattern: + // void foo() { + // return; + // } + // void test() { + // return foo(); + // } + if (RT.isNull() || !RT->isVoidType()) + emitUndef(C, RetE); return; + } - ExplodedNode *N = C.generateSink(); + if (RT.isNull()) + return; + + if (RT->isReferenceType()) { + checkReference(C, RetE, RetVal.castAs<DefinedOrUnknownSVal>()); + return; + } +} +static void emitBug(CheckerContext &C, BuiltinBug &BT, const Expr *RetE, + const Expr *TrackingE = 0) { + ExplodedNode *N = C.generateSink(); if (!N) return; - - if (!BT) - BT.reset(new BuiltinBug("Garbage return value", - "Undefined or garbage value returned to caller")); - - BugReport *report = - new BugReport(*BT, BT->getDescription(), N); - - report->addRange(RetE->getSourceRange()); - bugreporter::trackNullOrUndefValue(N, RetE, *report); - - C.emitReport(report); + + BugReport *Report = new BugReport(BT, BT.getDescription(), N); + + Report->addRange(RetE->getSourceRange()); + bugreporter::trackNullOrUndefValue(N, TrackingE ? TrackingE : RetE, *Report); + + C.emitReport(Report); +} + +void ReturnUndefChecker::emitUndef(CheckerContext &C, const Expr *RetE) const { + if (!BT_Undef) + BT_Undef.reset(new BuiltinBug("Garbage return value", + "Undefined or garbage value " + "returned to caller")); + emitBug(C, *BT_Undef, RetE); +} + +void ReturnUndefChecker::checkReference(CheckerContext &C, const Expr *RetE, + DefinedOrUnknownSVal RetVal) const { + ProgramStateRef StNonNull, StNull; + llvm::tie(StNonNull, StNull) = C.getState()->assume(RetVal); + + if (StNonNull) { + // Going forward, assume the location is non-null. + C.addTransition(StNonNull); + return; + } + + // The return value is known to be null. Emit a bug report. + if (!BT_NullReference) + BT_NullReference.reset(new BuiltinBug("Returning null reference")); + + emitBug(C, *BT_NullReference, RetE, bugreporter::getDerefExpr(RetE)); } void ento::registerReturnUndefChecker(CheckerManager &mgr) { |