StackAddrEscapeChecker.cpp revision ec8605f1d7ec846dbf51047bfd5c56d32d1ff91c
1f5d2ef4a61e70eb2bcc3f4872e7095cf19d20163Ted Kremenek//=== StackAddrEscapeChecker.cpp ----------------------------------*- C++ -*--// 21622a547971cee50e386b4cdfe62ed1fcee1036dZhongxing Xu// 31622a547971cee50e386b4cdfe62ed1fcee1036dZhongxing Xu// The LLVM Compiler Infrastructure 41622a547971cee50e386b4cdfe62ed1fcee1036dZhongxing Xu// 51622a547971cee50e386b4cdfe62ed1fcee1036dZhongxing Xu// This file is distributed under the University of Illinois Open Source 61622a547971cee50e386b4cdfe62ed1fcee1036dZhongxing Xu// License. See LICENSE.TXT for details. 71622a547971cee50e386b4cdfe62ed1fcee1036dZhongxing Xu// 81622a547971cee50e386b4cdfe62ed1fcee1036dZhongxing Xu//===----------------------------------------------------------------------===// 91622a547971cee50e386b4cdfe62ed1fcee1036dZhongxing Xu// 101622a547971cee50e386b4cdfe62ed1fcee1036dZhongxing Xu// This file defines stack address leak checker, which checks if an invalid 111622a547971cee50e386b4cdfe62ed1fcee1036dZhongxing Xu// stack address is stored into a global or heap location. See CERT DCL30-C. 121622a547971cee50e386b4cdfe62ed1fcee1036dZhongxing Xu// 131622a547971cee50e386b4cdfe62ed1fcee1036dZhongxing Xu//===----------------------------------------------------------------------===// 141622a547971cee50e386b4cdfe62ed1fcee1036dZhongxing Xu 15027a6abdd6cedc0b8203da72eed6d15c796dce9dArgyrios Kyrtzidis#include "ClangSACheckers.h" 16ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/Checker.h" 17695fb502825a53ccd178ec1c85c77929d88acb71Argyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/CheckerManager.h" 18af5800a1e287990bb547e052f257adeeae5ab476Argyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 199b663716449b618ba0390b1dbebc54fa8e971124Ted Kremenek#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 209b663716449b618ba0390b1dbebc54fa8e971124Ted Kremenek#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h" 219b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu#include "clang/Basic/SourceManager.h" 229b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu#include "llvm/ADT/SmallString.h" 231622a547971cee50e386b4cdfe62ed1fcee1036dZhongxing Xuusing namespace clang; 249ef6537a894c33003359b1f9b9676e9178e028b7Ted Kremenekusing namespace ento; 251622a547971cee50e386b4cdfe62ed1fcee1036dZhongxing Xu 261622a547971cee50e386b4cdfe62ed1fcee1036dZhongxing Xunamespace { 27ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidisclass StackAddrEscapeChecker : public Checker< check::PreStmt<ReturnStmt>, 28af5800a1e287990bb547e052f257adeeae5ab476Argyrios Kyrtzidis check::EndPath > { 29af5800a1e287990bb547e052f257adeeae5ab476Argyrios Kyrtzidis mutable llvm::OwningPtr<BuiltinBug> BT_stackleak; 30af5800a1e287990bb547e052f257adeeae5ab476Argyrios Kyrtzidis mutable llvm::OwningPtr<BuiltinBug> BT_returnstack; 311622a547971cee50e386b4cdfe62ed1fcee1036dZhongxing Xu 321622a547971cee50e386b4cdfe62ed1fcee1036dZhongxing Xupublic: 33af5800a1e287990bb547e052f257adeeae5ab476Argyrios Kyrtzidis void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const; 34af5800a1e287990bb547e052f257adeeae5ab476Argyrios Kyrtzidis void checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const; 359b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xuprivate: 36af5800a1e287990bb547e052f257adeeae5ab476Argyrios Kyrtzidis void EmitStackError(CheckerContext &C, const MemRegion *R, 37af5800a1e287990bb547e052f257adeeae5ab476Argyrios Kyrtzidis const Expr *RetE) const; 38af5800a1e287990bb547e052f257adeeae5ab476Argyrios Kyrtzidis static SourceRange GenName(llvm::raw_ostream &os, const MemRegion *R, 39af5800a1e287990bb547e052f257adeeae5ab476Argyrios Kyrtzidis SourceManager &SM); 401622a547971cee50e386b4cdfe62ed1fcee1036dZhongxing Xu}; 411622a547971cee50e386b4cdfe62ed1fcee1036dZhongxing Xu} 421622a547971cee50e386b4cdfe62ed1fcee1036dZhongxing Xu 43f5d2ef4a61e70eb2bcc3f4872e7095cf19d20163Ted KremenekSourceRange StackAddrEscapeChecker::GenName(llvm::raw_ostream &os, 44a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek const MemRegion *R, 45a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek SourceManager &SM) { 46a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek // Get the base region, stripping away fields and elements. 479b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu R = R->getBaseRegion(); 48a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek SourceRange range; 49a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek os << "Address of "; 50a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek 519b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu // Check if the region is a compound literal. 529b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu if (const CompoundLiteralRegion* CR = dyn_cast<CompoundLiteralRegion>(R)) { 539b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu const CompoundLiteralExpr* CL = CR->getLiteralExpr(); 54a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek os << "stack memory associated with a compound literal " 55a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek "declared on line " 56a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek << SM.getInstantiationLineNumber(CL->getLocStart()) 57a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek << " returned to caller"; 589b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu range = CL->getSourceRange(); 599b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu } 609b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu else if (const AllocaRegion* AR = dyn_cast<AllocaRegion>(R)) { 619b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu const Expr* ARE = AR->getExpr(); 629b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu SourceLocation L = ARE->getLocStart(); 639b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu range = ARE->getSourceRange(); 64a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek os << "stack memory allocated by call to alloca() on line " 65a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek << SM.getInstantiationLineNumber(L); 669b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu } 679b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu else if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) { 689b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu const BlockDecl *BD = BR->getCodeRegion()->getDecl(); 699b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu SourceLocation L = BD->getLocStart(); 709b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu range = BD->getSourceRange(); 71a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek os << "stack-allocated block declared on line " 72a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek << SM.getInstantiationLineNumber(L); 739b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu } 749b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu else if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { 75a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek os << "stack memory associated with local variable '" 76a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek << VR->getString() << '\''; 779b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu range = VR->getDecl()->getSourceRange(); 789b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu } 799b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu else { 809b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu assert(false && "Invalid region in ReturnStackAddressChecker."); 81a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek } 82a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek 83a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek return range; 84a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek} 85a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek 86f5d2ef4a61e70eb2bcc3f4872e7095cf19d20163Ted Kremenekvoid StackAddrEscapeChecker::EmitStackError(CheckerContext &C, const MemRegion *R, 87af5800a1e287990bb547e052f257adeeae5ab476Argyrios Kyrtzidis const Expr *RetE) const { 88d048c6ef5b6cfaa0cecb8cc1d4bdace32ed21d07Ted Kremenek ExplodedNode *N = C.generateSink(); 89a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek 90a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek if (!N) 919b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu return; 929b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu 93a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek if (!BT_returnstack) 94af5800a1e287990bb547e052f257adeeae5ab476Argyrios Kyrtzidis BT_returnstack.reset( 95af5800a1e287990bb547e052f257adeeae5ab476Argyrios Kyrtzidis new BuiltinBug("Return of address to stack-allocated memory")); 96a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek 97a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek // Generate a report for this bug. 98a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek llvm::SmallString<512> buf; 99a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek llvm::raw_svector_ostream os(buf); 100a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek SourceRange range = GenName(os, R, C.getSourceManager()); 101a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek os << " returned to caller"; 1029b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu RangedBugReport *report = new RangedBugReport(*BT_returnstack, os.str(), N); 1039b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu report->addRange(RetE->getSourceRange()); 1049b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu if (range.isValid()) 1059b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu report->addRange(range); 1069b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu 1079b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu C.EmitReport(report); 108a7e6845660f91ec611427e1db842780e1ec12bdbEli Friedman} 1099b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu 110f5d2ef4a61e70eb2bcc3f4872e7095cf19d20163Ted Kremenekvoid StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS, 111af5800a1e287990bb547e052f257adeeae5ab476Argyrios Kyrtzidis CheckerContext &C) const { 1129b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu 1139b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu const Expr *RetE = RS->getRetValue(); 1149b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu if (!RetE) 1159b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu return; 1169b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu 1179b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu SVal V = C.getState()->getSVal(RetE); 1189b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu const MemRegion *R = V.getAsRegion(); 1199b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu 1209b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu if (!R || !R->hasStackStorage()) 1219b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu return; 1229b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu 1239b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu if (R->hasStackStorage()) { 1249b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu EmitStackError(C, R, RetE); 1259b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu return; 1269b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu } 1279b1468311d625ac8920adda5440ce8ffb1a5a5d2Zhongxing Xu} 1281622a547971cee50e386b4cdfe62ed1fcee1036dZhongxing Xu 129f5d2ef4a61e70eb2bcc3f4872e7095cf19d20163Ted Kremenekvoid StackAddrEscapeChecker::checkEndPath(EndOfFunctionNodeBuilder &B, 130af5800a1e287990bb547e052f257adeeae5ab476Argyrios Kyrtzidis ExprEngine &Eng) const { 131ba37d3b2ef37c3591a4f673215d78cb9cc928de3Ted Kremenek 1321622a547971cee50e386b4cdfe62ed1fcee1036dZhongxing Xu const GRState *state = B.getState(); 133551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek 134551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek // Iterate over all bindings to global variables and see if it contains 135551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek // a memory region in the stack space. 136551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek class CallBack : public StoreManager::BindingsHandler { 137551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek private: 138551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek const StackFrameContext *CurSFC; 139551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek public: 140a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek llvm::SmallVector<std::pair<const MemRegion*, const MemRegion*>, 10> V; 141551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek 142551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek CallBack(const LocationContext *LCtx) 143a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek : CurSFC(LCtx->getCurrentStackFrame()) {} 144551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek 145551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek bool HandleBinding(StoreManager &SMgr, Store store, 146551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek const MemRegion *region, SVal val) { 147551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek 148551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek if (!isa<GlobalsSpaceRegion>(region->getMemorySpace())) 149551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek return true; 150551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek 151551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek const MemRegion *vR = val.getAsRegion(); 152551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek if (!vR) 153551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek return true; 154551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek 155551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek if (const StackSpaceRegion *SSR = 156551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek dyn_cast<StackSpaceRegion>(vR->getMemorySpace())) { 157551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek // If the global variable holds a location in the current stack frame, 158551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek // record the binding to emit a warning. 159a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek if (SSR->getStackFrame() == CurSFC) 160a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek V.push_back(std::make_pair(region, vR)); 1611622a547971cee50e386b4cdfe62ed1fcee1036dZhongxing Xu } 162551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek 163551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek return true; 1641622a547971cee50e386b4cdfe62ed1fcee1036dZhongxing Xu } 165551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek }; 166551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek 167551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek CallBack cb(B.getPredecessor()->getLocationContext()); 168551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek state->getStateManager().getStoreManager().iterBindings(state->getStore(),cb); 169a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek 170a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek if (cb.V.empty()) 171551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek return; 172551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek 173551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek // Generate an error node. 174f178ac8b68b29e44867777232ba8fee59edc4037Argyrios Kyrtzidis ExplodedNode *N = B.generateNode(state); 175551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek if (!N) 176551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek return; 177a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek 178551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek if (!BT_stackleak) 179af5800a1e287990bb547e052f257adeeae5ab476Argyrios Kyrtzidis BT_stackleak.reset( 180a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek new BuiltinBug("Stack address stored into global variable", 181a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek "Stack address was saved into a global variable. " 182a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek "This is dangerous because the address will become " 183af5800a1e287990bb547e052f257adeeae5ab476Argyrios Kyrtzidis "invalid after returning from the function")); 184551bd1f9191af0eecdc29764e34e01803c73ae31Ted Kremenek 185a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek for (unsigned i = 0, e = cb.V.size(); i != e; ++i) { 186a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek // Generate a report for this bug. 187a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek llvm::SmallString<512> buf; 188a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek llvm::raw_svector_ostream os(buf); 189a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek SourceRange range = GenName(os, cb.V[i].second, 190a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek Eng.getContext().getSourceManager()); 191a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek os << " is still referred to by the global variable '"; 192a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek const VarRegion *VR = cast<VarRegion>(cb.V[i].first->getBaseRegion()); 193a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek os << VR->getDecl()->getNameAsString() 194a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek << "' upon returning to the caller. This will be a dangling reference"; 195a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek RangedBugReport *report = new RangedBugReport(*BT_stackleak, os.str(), N); 196a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek if (range.isValid()) 197a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek report->addRange(range); 198a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek 199a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek Eng.getBugReporter().EmitReport(report); 200a8166156a6414ddd6a68514dc4f48e95d2259977Ted Kremenek } 2011622a547971cee50e386b4cdfe62ed1fcee1036dZhongxing Xu} 202af5800a1e287990bb547e052f257adeeae5ab476Argyrios Kyrtzidis 203f5d2ef4a61e70eb2bcc3f4872e7095cf19d20163Ted Kremenekvoid ento::registerStackAddrEscapeChecker(CheckerManager &mgr) { 204f5d2ef4a61e70eb2bcc3f4872e7095cf19d20163Ted Kremenek mgr.registerChecker<StackAddrEscapeChecker>(); 205af5800a1e287990bb547e052f257adeeae5ab476Argyrios Kyrtzidis} 206