clang API Documentation
00001 //=== StackAddrEscapeChecker.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 stack address leak checker, which checks if an invalid 00011 // stack address is stored into a global or heap location. See CERT DCL30-C. 00012 // 00013 //===----------------------------------------------------------------------===// 00014 00015 #include "ClangSACheckers.h" 00016 #include "clang/StaticAnalyzer/Core/Checker.h" 00017 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 00018 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 00019 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 00020 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" 00021 #include "clang/Basic/SourceManager.h" 00022 #include "llvm/ADT/SmallString.h" 00023 using namespace clang; 00024 using namespace ento; 00025 00026 namespace { 00027 class StackAddrEscapeChecker : public Checker< check::PreStmt<ReturnStmt>, 00028 check::EndPath > { 00029 mutable OwningPtr<BuiltinBug> BT_stackleak; 00030 mutable OwningPtr<BuiltinBug> BT_returnstack; 00031 00032 public: 00033 void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const; 00034 void checkEndPath(CheckerContext &Ctx) const; 00035 private: 00036 void EmitStackError(CheckerContext &C, const MemRegion *R, 00037 const Expr *RetE) const; 00038 static SourceRange GenName(raw_ostream &os, const MemRegion *R, 00039 SourceManager &SM); 00040 }; 00041 } 00042 00043 SourceRange StackAddrEscapeChecker::GenName(raw_ostream &os, 00044 const MemRegion *R, 00045 SourceManager &SM) { 00046 // Get the base region, stripping away fields and elements. 00047 R = R->getBaseRegion(); 00048 SourceRange range; 00049 os << "Address of "; 00050 00051 // Check if the region is a compound literal. 00052 if (const CompoundLiteralRegion* CR = dyn_cast<CompoundLiteralRegion>(R)) { 00053 const CompoundLiteralExpr *CL = CR->getLiteralExpr(); 00054 os << "stack memory associated with a compound literal " 00055 "declared on line " 00056 << SM.getExpansionLineNumber(CL->getLocStart()) 00057 << " returned to caller"; 00058 range = CL->getSourceRange(); 00059 } 00060 else if (const AllocaRegion* AR = dyn_cast<AllocaRegion>(R)) { 00061 const Expr *ARE = AR->getExpr(); 00062 SourceLocation L = ARE->getLocStart(); 00063 range = ARE->getSourceRange(); 00064 os << "stack memory allocated by call to alloca() on line " 00065 << SM.getExpansionLineNumber(L); 00066 } 00067 else if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) { 00068 const BlockDecl *BD = BR->getCodeRegion()->getDecl(); 00069 SourceLocation L = BD->getLocStart(); 00070 range = BD->getSourceRange(); 00071 os << "stack-allocated block declared on line " 00072 << SM.getExpansionLineNumber(L); 00073 } 00074 else if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { 00075 os << "stack memory associated with local variable '" 00076 << VR->getString() << '\''; 00077 range = VR->getDecl()->getSourceRange(); 00078 } 00079 else if (const CXXTempObjectRegion *TOR = dyn_cast<CXXTempObjectRegion>(R)) { 00080 os << "stack memory associated with temporary object of type '" 00081 << TOR->getValueType().getAsString() << '\''; 00082 range = TOR->getExpr()->getSourceRange(); 00083 } 00084 else { 00085 llvm_unreachable("Invalid region in ReturnStackAddressChecker."); 00086 } 00087 00088 return range; 00089 } 00090 00091 void StackAddrEscapeChecker::EmitStackError(CheckerContext &C, const MemRegion *R, 00092 const Expr *RetE) const { 00093 ExplodedNode *N = C.generateSink(); 00094 00095 if (!N) 00096 return; 00097 00098 if (!BT_returnstack) 00099 BT_returnstack.reset( 00100 new BuiltinBug("Return of address to stack-allocated memory")); 00101 00102 // Generate a report for this bug. 00103 SmallString<512> buf; 00104 llvm::raw_svector_ostream os(buf); 00105 SourceRange range = GenName(os, R, C.getSourceManager()); 00106 os << " returned to caller"; 00107 BugReport *report = new BugReport(*BT_returnstack, os.str(), N); 00108 report->addRange(RetE->getSourceRange()); 00109 if (range.isValid()) 00110 report->addRange(range); 00111 00112 C.EmitReport(report); 00113 } 00114 00115 void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS, 00116 CheckerContext &C) const { 00117 00118 const Expr *RetE = RS->getRetValue(); 00119 if (!RetE) 00120 return; 00121 00122 SVal V = C.getState()->getSVal(RetE, C.getLocationContext()); 00123 const MemRegion *R = V.getAsRegion(); 00124 00125 if (!R) 00126 return; 00127 00128 const StackSpaceRegion *SS = 00129 dyn_cast_or_null<StackSpaceRegion>(R->getMemorySpace()); 00130 00131 if (!SS) 00132 return; 00133 00134 // Return stack memory in an ancestor stack frame is fine. 00135 const StackFrameContext *SFC = SS->getStackFrame(); 00136 if (SFC != C.getLocationContext()->getCurrentStackFrame()) 00137 return; 00138 00139 // Automatic reference counting automatically copies blocks. 00140 if (C.getASTContext().getLangOpts().ObjCAutoRefCount && 00141 isa<BlockDataRegion>(R)) 00142 return; 00143 00144 EmitStackError(C, R, RetE); 00145 } 00146 00147 void StackAddrEscapeChecker::checkEndPath(CheckerContext &Ctx) const { 00148 ProgramStateRef state = Ctx.getState(); 00149 00150 // Iterate over all bindings to global variables and see if it contains 00151 // a memory region in the stack space. 00152 class CallBack : public StoreManager::BindingsHandler { 00153 private: 00154 CheckerContext &Ctx; 00155 const StackFrameContext *CurSFC; 00156 public: 00157 SmallVector<std::pair<const MemRegion*, const MemRegion*>, 10> V; 00158 00159 CallBack(CheckerContext &CC) : 00160 Ctx(CC), 00161 CurSFC(CC.getLocationContext()->getCurrentStackFrame()) 00162 {} 00163 00164 bool HandleBinding(StoreManager &SMgr, Store store, 00165 const MemRegion *region, SVal val) { 00166 00167 if (!isa<GlobalsSpaceRegion>(region->getMemorySpace())) 00168 return true; 00169 00170 const MemRegion *vR = val.getAsRegion(); 00171 if (!vR) 00172 return true; 00173 00174 // Under automated retain release, it is okay to assign a block 00175 // directly to a global variable. 00176 if (Ctx.getASTContext().getLangOpts().ObjCAutoRefCount && 00177 isa<BlockDataRegion>(vR)) 00178 return true; 00179 00180 if (const StackSpaceRegion *SSR = 00181 dyn_cast<StackSpaceRegion>(vR->getMemorySpace())) { 00182 // If the global variable holds a location in the current stack frame, 00183 // record the binding to emit a warning. 00184 if (SSR->getStackFrame() == CurSFC) 00185 V.push_back(std::make_pair(region, vR)); 00186 } 00187 00188 return true; 00189 } 00190 }; 00191 00192 CallBack cb(Ctx); 00193 state->getStateManager().getStoreManager().iterBindings(state->getStore(),cb); 00194 00195 if (cb.V.empty()) 00196 return; 00197 00198 // Generate an error node. 00199 ExplodedNode *N = Ctx.addTransition(state); 00200 if (!N) 00201 return; 00202 00203 if (!BT_stackleak) 00204 BT_stackleak.reset( 00205 new BuiltinBug("Stack address stored into global variable", 00206 "Stack address was saved into a global variable. " 00207 "This is dangerous because the address will become " 00208 "invalid after returning from the function")); 00209 00210 for (unsigned i = 0, e = cb.V.size(); i != e; ++i) { 00211 // Generate a report for this bug. 00212 SmallString<512> buf; 00213 llvm::raw_svector_ostream os(buf); 00214 SourceRange range = GenName(os, cb.V[i].second, 00215 Ctx.getSourceManager()); 00216 os << " is still referred to by the global variable '"; 00217 const VarRegion *VR = cast<VarRegion>(cb.V[i].first->getBaseRegion()); 00218 os << *VR->getDecl() 00219 << "' upon returning to the caller. This will be a dangling reference"; 00220 BugReport *report = new BugReport(*BT_stackleak, os.str(), N); 00221 if (range.isValid()) 00222 report->addRange(range); 00223 00224 Ctx.EmitReport(report); 00225 } 00226 } 00227 00228 void ento::registerStackAddrEscapeChecker(CheckerManager &mgr) { 00229 mgr.registerChecker<StackAddrEscapeChecker>(); 00230 }