ReturnPointerRangeChecker.cpp revision 8bef8238181a30e52dea380789a7e2d760eac532
1//== ReturnPointerRangeChecker.cpp ------------------------------*- C++ -*--==// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file defines ReturnPointerRangeChecker, which is a path-sensitive check 11// which looks for an out-of-bound pointer being returned to callers. 12// 13//===----------------------------------------------------------------------===// 14 15#include "ClangSACheckers.h" 16#include "clang/StaticAnalyzer/Core/Checker.h" 17#include "clang/StaticAnalyzer/Core/CheckerManager.h" 18#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 19#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 20#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" 21 22using namespace clang; 23using namespace ento; 24 25namespace { 26class ReturnPointerRangeChecker : 27 public Checker< check::PreStmt<ReturnStmt> > { 28 mutable llvm::OwningPtr<BuiltinBug> BT; 29public: 30 void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const; 31}; 32} 33 34void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS, 35 CheckerContext &C) const { 36 ProgramStateRef state = C.getState(); 37 38 const Expr *RetE = RS->getRetValue(); 39 if (!RetE) 40 return; 41 42 SVal V = state->getSVal(RetE, C.getLocationContext()); 43 const MemRegion *R = V.getAsRegion(); 44 45 const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(R); 46 if (!ER) 47 return; 48 49 DefinedOrUnknownSVal Idx = cast<DefinedOrUnknownSVal>(ER->getIndex()); 50 // Zero index is always in bound, this also passes ElementRegions created for 51 // pointer casts. 52 if (Idx.isZeroConstant()) 53 return; 54 // FIXME: All of this out-of-bounds checking should eventually be refactored 55 // into a common place. 56 57 DefinedOrUnknownSVal NumElements 58 = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(), 59 ER->getValueType()); 60 61 ProgramStateRef StInBound = state->assumeInBound(Idx, NumElements, true); 62 ProgramStateRef StOutBound = state->assumeInBound(Idx, NumElements, false); 63 if (StOutBound && !StInBound) { 64 ExplodedNode *N = C.generateSink(StOutBound); 65 66 if (!N) 67 return; 68 69 // FIXME: This bug correspond to CWE-466. Eventually we should have bug 70 // types explicitly reference such exploit categories (when applicable). 71 if (!BT) 72 BT.reset(new BuiltinBug("Return of pointer value outside of expected range", 73 "Returned pointer value points outside the original object " 74 "(potential buffer overflow)")); 75 76 // FIXME: It would be nice to eventually make this diagnostic more clear, 77 // e.g., by referencing the original declaration or by saying *why* this 78 // reference is outside the range. 79 80 // Generate a report for this bug. 81 BugReport *report = 82 new BugReport(*BT, BT->getDescription(), N); 83 84 report->addRange(RetE->getSourceRange()); 85 C.EmitReport(report); 86 } 87} 88 89void ento::registerReturnPointerRangeChecker(CheckerManager &mgr) { 90 mgr.registerChecker<ReturnPointerRangeChecker>(); 91} 92