ReturnPointerRangeChecker.cpp 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. //== ReturnPointerRangeChecker.cpp ------------------------------*- C++ -*--==//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. //
  10. // This file defines ReturnPointerRangeChecker, which is a path-sensitive check
  11. // which looks for an out-of-bound pointer being returned to callers.
  12. //
  13. //===----------------------------------------------------------------------===//
  14. #include "ClangSACheckers.h"
  15. #include "clang/StaticAnalyzer/Core/Checker.h"
  16. #include "clang/StaticAnalyzer/Core/CheckerManager.h"
  17. #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
  18. #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
  19. #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
  20. using namespace clang;
  21. using namespace ento;
  22. namespace {
  23. class ReturnPointerRangeChecker :
  24. public Checker< check::PreStmt<ReturnStmt> > {
  25. mutable llvm::OwningPtr<BuiltinBug> BT;
  26. public:
  27. void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const;
  28. };
  29. }
  30. void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS,
  31. CheckerContext &C) const {
  32. const ProgramState *state = C.getState();
  33. const Expr *RetE = RS->getRetValue();
  34. if (!RetE)
  35. return;
  36. SVal V = state->getSVal(RetE);
  37. const MemRegion *R = V.getAsRegion();
  38. const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(R);
  39. if (!ER)
  40. return;
  41. DefinedOrUnknownSVal Idx = cast<DefinedOrUnknownSVal>(ER->getIndex());
  42. // Zero index is always in bound, this also passes ElementRegions created for
  43. // pointer casts.
  44. if (Idx.isZeroConstant())
  45. return;
  46. // FIXME: All of this out-of-bounds checking should eventually be refactored
  47. // into a common place.
  48. DefinedOrUnknownSVal NumElements
  49. = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(),
  50. ER->getValueType());
  51. const ProgramState *StInBound = state->assumeInBound(Idx, NumElements, true);
  52. const ProgramState *StOutBound = state->assumeInBound(Idx, NumElements, false);
  53. if (StOutBound && !StInBound) {
  54. ExplodedNode *N = C.generateSink(StOutBound);
  55. if (!N)
  56. return;
  57. // FIXME: This bug correspond to CWE-466. Eventually we should have bug
  58. // types explicitly reference such exploit categories (when applicable).
  59. if (!BT)
  60. BT.reset(new BuiltinBug("Return of pointer value outside of expected range",
  61. "Returned pointer value points outside the original object "
  62. "(potential buffer overflow)"));
  63. // FIXME: It would be nice to eventually make this diagnostic more clear,
  64. // e.g., by referencing the original declaration or by saying *why* this
  65. // reference is outside the range.
  66. // Generate a report for this bug.
  67. BugReport *report =
  68. new BugReport(*BT, BT->getDescription(), N);
  69. report->addRange(RetE->getSourceRange());
  70. C.EmitReport(report);
  71. }
  72. }
  73. void ento::registerReturnPointerRangeChecker(CheckerManager &mgr) {
  74. mgr.registerChecker<ReturnPointerRangeChecker>();
  75. }