clang API Documentation

ReturnPointerRangeChecker.cpp
Go to the documentation of this file.
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 }