clang API Documentation
00001 //== ReturnPointerRangeChecker.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 ReturnPointerRangeChecker, which is a path-sensitive check 00011 // which looks for an out-of-bound pointer being returned to callers. 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/ExprEngine.h" 00021 00022 using namespace clang; 00023 using namespace ento; 00024 00025 namespace { 00026 class ReturnPointerRangeChecker : 00027 public Checker< check::PreStmt<ReturnStmt> > { 00028 mutable OwningPtr<BuiltinBug> BT; 00029 public: 00030 void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const; 00031 }; 00032 } 00033 00034 void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS, 00035 CheckerContext &C) const { 00036 ProgramStateRef state = C.getState(); 00037 00038 const Expr *RetE = RS->getRetValue(); 00039 if (!RetE) 00040 return; 00041 00042 SVal V = state->getSVal(RetE, C.getLocationContext()); 00043 const MemRegion *R = V.getAsRegion(); 00044 00045 const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(R); 00046 if (!ER) 00047 return; 00048 00049 DefinedOrUnknownSVal Idx = cast<DefinedOrUnknownSVal>(ER->getIndex()); 00050 // Zero index is always in bound, this also passes ElementRegions created for 00051 // pointer casts. 00052 if (Idx.isZeroConstant()) 00053 return; 00054 // FIXME: All of this out-of-bounds checking should eventually be refactored 00055 // into a common place. 00056 00057 DefinedOrUnknownSVal NumElements 00058 = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(), 00059 ER->getValueType()); 00060 00061 ProgramStateRef StInBound = state->assumeInBound(Idx, NumElements, true); 00062 ProgramStateRef StOutBound = state->assumeInBound(Idx, NumElements, false); 00063 if (StOutBound && !StInBound) { 00064 ExplodedNode *N = C.generateSink(StOutBound); 00065 00066 if (!N) 00067 return; 00068 00069 // FIXME: This bug correspond to CWE-466. Eventually we should have bug 00070 // types explicitly reference such exploit categories (when applicable). 00071 if (!BT) 00072 BT.reset(new BuiltinBug("Return of pointer value outside of expected range", 00073 "Returned pointer value points outside the original object " 00074 "(potential buffer overflow)")); 00075 00076 // FIXME: It would be nice to eventually make this diagnostic more clear, 00077 // e.g., by referencing the original declaration or by saying *why* this 00078 // reference is outside the range. 00079 00080 // Generate a report for this bug. 00081 BugReport *report = 00082 new BugReport(*BT, BT->getDescription(), N); 00083 00084 report->addRange(RetE->getSourceRange()); 00085 C.EmitReport(report); 00086 } 00087 } 00088 00089 void ento::registerReturnPointerRangeChecker(CheckerManager &mgr) { 00090 mgr.registerChecker<ReturnPointerRangeChecker>(); 00091 }