clang API Documentation
00001 //== ReturnUndefChecker.cpp -------------------------------------*- C++ -*--==// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file defines ReturnUndefChecker, which is a path-sensitive 00011 // check which looks for undefined or garbage values being returned to the 00012 // caller. 00013 // 00014 //===----------------------------------------------------------------------===// 00015 00016 #include "ClangSACheckers.h" 00017 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 00018 #include "clang/StaticAnalyzer/Core/Checker.h" 00019 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 00020 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 00021 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 00022 00023 using namespace clang; 00024 using namespace ento; 00025 00026 namespace { 00027 class ReturnUndefChecker : public Checker< check::PreStmt<ReturnStmt> > { 00028 mutable std::unique_ptr<BuiltinBug> BT_Undef; 00029 mutable std::unique_ptr<BuiltinBug> BT_NullReference; 00030 00031 void emitUndef(CheckerContext &C, const Expr *RetE) const; 00032 void checkReference(CheckerContext &C, const Expr *RetE, 00033 DefinedOrUnknownSVal RetVal) const; 00034 public: 00035 void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const; 00036 }; 00037 } 00038 00039 void ReturnUndefChecker::checkPreStmt(const ReturnStmt *RS, 00040 CheckerContext &C) const { 00041 const Expr *RetE = RS->getRetValue(); 00042 if (!RetE) 00043 return; 00044 SVal RetVal = C.getSVal(RetE); 00045 00046 const StackFrameContext *SFC = C.getStackFrame(); 00047 QualType RT = CallEvent::getDeclaredResultType(SFC->getDecl()); 00048 00049 if (RetVal.isUndef()) { 00050 // "return;" is modeled to evaluate to an UndefinedVal. Allow UndefinedVal 00051 // to be returned in functions returning void to support this pattern: 00052 // void foo() { 00053 // return; 00054 // } 00055 // void test() { 00056 // return foo(); 00057 // } 00058 if (!RT.isNull() && RT->isVoidType()) 00059 return; 00060 00061 // Not all blocks have explicitly-specified return types; if the return type 00062 // is not available, but the return value expression has 'void' type, assume 00063 // Sema already checked it. 00064 if (RT.isNull() && isa<BlockDecl>(SFC->getDecl()) && 00065 RetE->getType()->isVoidType()) 00066 return; 00067 00068 emitUndef(C, RetE); 00069 return; 00070 } 00071 00072 if (RT.isNull()) 00073 return; 00074 00075 if (RT->isReferenceType()) { 00076 checkReference(C, RetE, RetVal.castAs<DefinedOrUnknownSVal>()); 00077 return; 00078 } 00079 } 00080 00081 static void emitBug(CheckerContext &C, BuiltinBug &BT, const Expr *RetE, 00082 const Expr *TrackingE = nullptr) { 00083 ExplodedNode *N = C.generateSink(); 00084 if (!N) 00085 return; 00086 00087 BugReport *Report = new BugReport(BT, BT.getDescription(), N); 00088 00089 Report->addRange(RetE->getSourceRange()); 00090 bugreporter::trackNullOrUndefValue(N, TrackingE ? TrackingE : RetE, *Report); 00091 00092 C.emitReport(Report); 00093 } 00094 00095 void ReturnUndefChecker::emitUndef(CheckerContext &C, const Expr *RetE) const { 00096 if (!BT_Undef) 00097 BT_Undef.reset( 00098 new BuiltinBug(this, "Garbage return value", 00099 "Undefined or garbage value returned to caller")); 00100 emitBug(C, *BT_Undef, RetE); 00101 } 00102 00103 void ReturnUndefChecker::checkReference(CheckerContext &C, const Expr *RetE, 00104 DefinedOrUnknownSVal RetVal) const { 00105 ProgramStateRef StNonNull, StNull; 00106 std::tie(StNonNull, StNull) = C.getState()->assume(RetVal); 00107 00108 if (StNonNull) { 00109 // Going forward, assume the location is non-null. 00110 C.addTransition(StNonNull); 00111 return; 00112 } 00113 00114 // The return value is known to be null. Emit a bug report. 00115 if (!BT_NullReference) 00116 BT_NullReference.reset(new BuiltinBug(this, "Returning null reference")); 00117 00118 emitBug(C, *BT_NullReference, RetE, bugreporter::getDerefExpr(RetE)); 00119 } 00120 00121 void ento::registerReturnUndefChecker(CheckerManager &mgr) { 00122 mgr.registerChecker<ReturnUndefChecker>(); 00123 }