clang API Documentation
00001 //== ArrayBoundChecker.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 ArrayBoundChecker, which is a path-sensitive check 00011 // which looks for an out-of-bound array element access. 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 ArrayBoundChecker : 00027 public Checker<check::Location> { 00028 mutable OwningPtr<BuiltinBug> BT; 00029 public: 00030 void checkLocation(SVal l, bool isLoad, const Stmt* S, 00031 CheckerContext &C) const; 00032 }; 00033 } 00034 00035 void ArrayBoundChecker::checkLocation(SVal l, bool isLoad, const Stmt* LoadS, 00036 CheckerContext &C) const { 00037 // Check for out of bound array element access. 00038 const MemRegion *R = l.getAsRegion(); 00039 if (!R) 00040 return; 00041 00042 const ElementRegion *ER = dyn_cast<ElementRegion>(R); 00043 if (!ER) 00044 return; 00045 00046 // Get the index of the accessed element. 00047 DefinedOrUnknownSVal Idx = cast<DefinedOrUnknownSVal>(ER->getIndex()); 00048 00049 // Zero index is always in bound, this also passes ElementRegions created for 00050 // pointer casts. 00051 if (Idx.isZeroConstant()) 00052 return; 00053 00054 ProgramStateRef state = C.getState(); 00055 00056 // Get the size of the array. 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 if (!N) 00066 return; 00067 00068 if (!BT) 00069 BT.reset(new BuiltinBug("Out-of-bound array access", 00070 "Access out-of-bound array element (buffer overflow)")); 00071 00072 // FIXME: It would be nice to eventually make this diagnostic more clear, 00073 // e.g., by referencing the original declaration or by saying *why* this 00074 // reference is outside the range. 00075 00076 // Generate a report for this bug. 00077 BugReport *report = 00078 new BugReport(*BT, BT->getDescription(), N); 00079 00080 report->addRange(LoadS->getSourceRange()); 00081 C.EmitReport(report); 00082 return; 00083 } 00084 00085 // Array bound check succeeded. From this point forward the array bound 00086 // should always succeed. 00087 C.addTransition(StInBound); 00088 } 00089 00090 void ento::registerArrayBoundChecker(CheckerManager &mgr) { 00091 mgr.registerChecker<ArrayBoundChecker>(); 00092 }