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