ReturnPointerRangeChecker.cpp revision 9b663716449b618ba0390b1dbebc54fa8e971124
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 "InternalChecks.h" 16#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 17#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h" 18#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" 19 20using namespace clang; 21using namespace ento; 22 23namespace { 24class ReturnPointerRangeChecker : 25 public CheckerVisitor<ReturnPointerRangeChecker> { 26 BuiltinBug *BT; 27public: 28 ReturnPointerRangeChecker() : BT(0) {} 29 static void *getTag(); 30 void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS); 31}; 32} 33 34void ento::RegisterReturnPointerRangeChecker(ExprEngine &Eng) { 35 Eng.registerCheck(new ReturnPointerRangeChecker()); 36} 37 38void *ReturnPointerRangeChecker::getTag() { 39 static int x = 0; return &x; 40} 41 42void ReturnPointerRangeChecker::PreVisitReturnStmt(CheckerContext &C, 43 const ReturnStmt *RS) { 44 const GRState *state = C.getState(); 45 46 const Expr *RetE = RS->getRetValue(); 47 if (!RetE) 48 return; 49 50 SVal V = state->getSVal(RetE); 51 const MemRegion *R = V.getAsRegion(); 52 53 const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(R); 54 if (!ER) 55 return; 56 57 DefinedOrUnknownSVal Idx = cast<DefinedOrUnknownSVal>(ER->getIndex()); 58 // Zero index is always in bound, this also passes ElementRegions created for 59 // pointer casts. 60 if (Idx.isZeroConstant()) 61 return; 62 // FIXME: All of this out-of-bounds checking should eventually be refactored 63 // into a common place. 64 65 DefinedOrUnknownSVal NumElements 66 = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(), 67 ER->getValueType()); 68 69 const GRState *StInBound = state->assumeInBound(Idx, NumElements, true); 70 const GRState *StOutBound = state->assumeInBound(Idx, NumElements, false); 71 if (StOutBound && !StInBound) { 72 ExplodedNode *N = C.generateSink(StOutBound); 73 74 if (!N) 75 return; 76 77 // FIXME: This bug correspond to CWE-466. Eventually we should have bug 78 // types explicitly reference such exploit categories (when applicable). 79 if (!BT) 80 BT = new BuiltinBug("Return of pointer value outside of expected range", 81 "Returned pointer value points outside the original object " 82 "(potential buffer overflow)"); 83 84 // FIXME: It would be nice to eventually make this diagnostic more clear, 85 // e.g., by referencing the original declaration or by saying *why* this 86 // reference is outside the range. 87 88 // Generate a report for this bug. 89 RangedBugReport *report = 90 new RangedBugReport(*BT, BT->getDescription(), N); 91 92 report->addRange(RetE->getSourceRange()); 93 C.EmitReport(report); 94 } 95} 96