VLASizeChecker.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. //=== VLASizeChecker.cpp - Undefined dereference checker --------*- 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 defines VLASizeChecker, a builtin check in ExprEngine that
  11. // performs checks for declaration of VLA of undefined or zero size.
  12. // In addition, VLASizeChecker is responsible for defining the extent
  13. // of the MemRegion that represents a VLA.
  14. //
  15. //===----------------------------------------------------------------------===//
  16. #include "InternalChecks.h"
  17. #include "clang/AST/CharUnits.h"
  18. #include "clang/StaticAnalyzer/BugReporter/BugType.h"
  19. #include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
  20. #include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
  21. using namespace clang;
  22. using namespace ento;
  23. namespace {
  24. class VLASizeChecker : public CheckerVisitor<VLASizeChecker> {
  25. BugType *BT_zero;
  26. BugType *BT_undef;
  27. public:
  28. VLASizeChecker() : BT_zero(0), BT_undef(0) {}
  29. static void *getTag() { static int tag = 0; return &tag; }
  30. void PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS);
  31. };
  32. } // end anonymous namespace
  33. void ento::RegisterVLASizeChecker(ExprEngine &Eng) {
  34. Eng.registerCheck(new VLASizeChecker());
  35. }
  36. void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) {
  37. if (!DS->isSingleDecl())
  38. return;
  39. const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
  40. if (!VD)
  41. return;
  42. ASTContext &Ctx = C.getASTContext();
  43. const VariableArrayType *VLA = Ctx.getAsVariableArrayType(VD->getType());
  44. if (!VLA)
  45. return;
  46. // FIXME: Handle multi-dimensional VLAs.
  47. const Expr* SE = VLA->getSizeExpr();
  48. const GRState *state = C.getState();
  49. SVal sizeV = state->getSVal(SE);
  50. if (sizeV.isUndef()) {
  51. // Generate an error node.
  52. ExplodedNode *N = C.generateSink();
  53. if (!N)
  54. return;
  55. if (!BT_undef)
  56. BT_undef = new BuiltinBug("Declared variable-length array (VLA) uses a "
  57. "garbage value as its size");
  58. EnhancedBugReport *report =
  59. new EnhancedBugReport(*BT_undef, BT_undef->getName(), N);
  60. report->addRange(SE->getSourceRange());
  61. report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE);
  62. C.EmitReport(report);
  63. return;
  64. }
  65. // See if the size value is known. It can't be undefined because we would have
  66. // warned about that already.
  67. if (sizeV.isUnknown())
  68. return;
  69. // Check if the size is zero.
  70. DefinedSVal sizeD = cast<DefinedSVal>(sizeV);
  71. const GRState *stateNotZero, *stateZero;
  72. llvm::tie(stateNotZero, stateZero) = state->assume(sizeD);
  73. if (stateZero && !stateNotZero) {
  74. ExplodedNode* N = C.generateSink(stateZero);
  75. if (!BT_zero)
  76. BT_zero = new BuiltinBug("Declared variable-length array (VLA) has zero "
  77. "size");
  78. EnhancedBugReport *report =
  79. new EnhancedBugReport(*BT_zero, BT_zero->getName(), N);
  80. report->addRange(SE->getSourceRange());
  81. report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE);
  82. C.EmitReport(report);
  83. return;
  84. }
  85. // From this point on, assume that the size is not zero.
  86. state = stateNotZero;
  87. // VLASizeChecker is responsible for defining the extent of the array being
  88. // declared. We do this by multiplying the array length by the element size,
  89. // then matching that with the array region's extent symbol.
  90. // Convert the array length to size_t.
  91. SValBuilder &svalBuilder = C.getSValBuilder();
  92. QualType SizeTy = Ctx.getSizeType();
  93. NonLoc ArrayLength = cast<NonLoc>(svalBuilder.evalCast(sizeD, SizeTy,
  94. SE->getType()));
  95. // Get the element size.
  96. CharUnits EleSize = Ctx.getTypeSizeInChars(VLA->getElementType());
  97. SVal EleSizeVal = svalBuilder.makeIntVal(EleSize.getQuantity(), SizeTy);
  98. // Multiply the array length by the element size.
  99. SVal ArraySizeVal = svalBuilder.evalBinOpNN(state, BO_Mul, ArrayLength,
  100. cast<NonLoc>(EleSizeVal), SizeTy);
  101. // Finally, assume that the array's extent matches the given size.
  102. const LocationContext *LC = C.getPredecessor()->getLocationContext();
  103. DefinedOrUnknownSVal Extent =
  104. state->getRegion(VD, LC)->getExtent(svalBuilder);
  105. DefinedOrUnknownSVal ArraySize = cast<DefinedOrUnknownSVal>(ArraySizeVal);
  106. DefinedOrUnknownSVal sizeIsKnown =
  107. svalBuilder.evalEQ(state, Extent, ArraySize);
  108. state = state->assume(sizeIsKnown, true);
  109. // Assume should not fail at this point.
  110. assert(state);
  111. // Remember our assumptions!
  112. C.addTransition(state);
  113. }