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