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