1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" |
17 | #include "clang/AST/CharUnits.h" |
18 | #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" |
19 | #include "clang/StaticAnalyzer/Core/Checker.h" |
20 | #include "clang/StaticAnalyzer/Core/CheckerManager.h" |
21 | #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" |
22 | #include "llvm/ADT/STLExtras.h" |
23 | #include "llvm/ADT/SmallString.h" |
24 | #include "llvm/Support/raw_ostream.h" |
25 | |
26 | using namespace clang; |
27 | using namespace ento; |
28 | |
29 | namespace { |
30 | class VLASizeChecker : public Checker< check::PreStmt<DeclStmt> > { |
31 | mutable std::unique_ptr<BugType> BT; |
32 | enum VLASize_Kind { VLA_Garbage, VLA_Zero, VLA_Tainted, VLA_Negative }; |
33 | |
34 | void reportBug(VLASize_Kind Kind, const Expr *SizeE, ProgramStateRef State, |
35 | CheckerContext &C, |
36 | std::unique_ptr<BugReporterVisitor> Visitor = nullptr) const; |
37 | |
38 | public: |
39 | void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const; |
40 | }; |
41 | } |
42 | |
43 | void VLASizeChecker::reportBug( |
44 | VLASize_Kind Kind, const Expr *SizeE, ProgramStateRef State, |
45 | CheckerContext &C, std::unique_ptr<BugReporterVisitor> Visitor) const { |
46 | |
47 | ExplodedNode *N = C.generateErrorNode(State); |
48 | if (!N) |
49 | return; |
50 | |
51 | if (!BT) |
52 | BT.reset(new BuiltinBug( |
53 | this, "Dangerous variable-length array (VLA) declaration")); |
54 | |
55 | SmallString<256> buf; |
56 | llvm::raw_svector_ostream os(buf); |
57 | os << "Declared variable-length array (VLA) "; |
58 | switch (Kind) { |
59 | case VLA_Garbage: |
60 | os << "uses a garbage value as its size"; |
61 | break; |
62 | case VLA_Zero: |
63 | os << "has zero size"; |
64 | break; |
65 | case VLA_Tainted: |
66 | os << "has tainted size"; |
67 | break; |
68 | case VLA_Negative: |
69 | os << "has negative size"; |
70 | break; |
71 | } |
72 | |
73 | auto report = llvm::make_unique<BugReport>(*BT, os.str(), N); |
74 | report->addVisitor(std::move(Visitor)); |
75 | report->addRange(SizeE->getSourceRange()); |
76 | bugreporter::trackExpressionValue(N, SizeE, *report); |
77 | C.emitReport(std::move(report)); |
78 | } |
79 | |
80 | void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const { |
81 | if (!DS->isSingleDecl()) |
82 | return; |
83 | |
84 | const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl()); |
85 | if (!VD) |
86 | return; |
87 | |
88 | ASTContext &Ctx = C.getASTContext(); |
89 | const VariableArrayType *VLA = Ctx.getAsVariableArrayType(VD->getType()); |
90 | if (!VLA) |
91 | return; |
92 | |
93 | |
94 | const Expr *SE = VLA->getSizeExpr(); |
95 | ProgramStateRef state = C.getState(); |
96 | SVal sizeV = C.getSVal(SE); |
97 | |
98 | if (sizeV.isUndef()) { |
99 | reportBug(VLA_Garbage, SE, state, C); |
100 | return; |
101 | } |
102 | |
103 | |
104 | |
105 | if (sizeV.isUnknown()) |
106 | return; |
107 | |
108 | |
109 | if (state->isTainted(sizeV)) { |
110 | reportBug(VLA_Tainted, SE, nullptr, C, |
111 | llvm::make_unique<TaintBugVisitor>(sizeV)); |
112 | return; |
113 | } |
114 | |
115 | |
116 | DefinedSVal sizeD = sizeV.castAs<DefinedSVal>(); |
117 | |
118 | ProgramStateRef stateNotZero, stateZero; |
119 | std::tie(stateNotZero, stateZero) = state->assume(sizeD); |
120 | |
121 | if (stateZero && !stateNotZero) { |
122 | reportBug(VLA_Zero, SE, stateZero, C); |
123 | return; |
124 | } |
125 | |
126 | |
127 | state = stateNotZero; |
128 | |
129 | |
130 | |
131 | |
132 | |
133 | |
134 | SValBuilder &svalBuilder = C.getSValBuilder(); |
135 | |
136 | QualType Ty = SE->getType(); |
137 | DefinedOrUnknownSVal Zero = svalBuilder.makeZeroVal(Ty); |
138 | |
139 | SVal LessThanZeroVal = svalBuilder.evalBinOp(state, BO_LT, sizeD, Zero, Ty); |
140 | if (Optional<DefinedSVal> LessThanZeroDVal = |
141 | LessThanZeroVal.getAs<DefinedSVal>()) { |
142 | ConstraintManager &CM = C.getConstraintManager(); |
143 | ProgramStateRef StatePos, StateNeg; |
144 | |
145 | std::tie(StateNeg, StatePos) = CM.assumeDual(state, *LessThanZeroDVal); |
146 | if (StateNeg && !StatePos) { |
147 | reportBug(VLA_Negative, SE, state, C); |
148 | return; |
149 | } |
150 | state = StatePos; |
151 | } |
152 | |
153 | |
154 | QualType SizeTy = Ctx.getSizeType(); |
155 | NonLoc ArrayLength = |
156 | svalBuilder.evalCast(sizeD, SizeTy, SE->getType()).castAs<NonLoc>(); |
157 | |
158 | |
159 | CharUnits EleSize = Ctx.getTypeSizeInChars(VLA->getElementType()); |
160 | SVal EleSizeVal = svalBuilder.makeIntVal(EleSize.getQuantity(), SizeTy); |
161 | |
162 | |
163 | SVal ArraySizeVal = svalBuilder.evalBinOpNN( |
164 | state, BO_Mul, ArrayLength, EleSizeVal.castAs<NonLoc>(), SizeTy); |
165 | |
166 | |
167 | const LocationContext *LC = C.getLocationContext(); |
168 | DefinedOrUnknownSVal Extent = |
169 | state->getRegion(VD, LC)->getExtent(svalBuilder); |
170 | DefinedOrUnknownSVal ArraySize = ArraySizeVal.castAs<DefinedOrUnknownSVal>(); |
171 | DefinedOrUnknownSVal sizeIsKnown = |
172 | svalBuilder.evalEQ(state, Extent, ArraySize); |
173 | state = state->assume(sizeIsKnown, true); |
174 | |
175 | |
176 | assert(state); |
177 | |
178 | |
179 | C.addTransition(state); |
180 | } |
181 | |
182 | void ento::registerVLASizeChecker(CheckerManager &mgr) { |
183 | mgr.registerChecker<VLASizeChecker>(); |
184 | } |
185 | |
186 | bool ento::shouldRegisterVLASizeChecker(const LangOptions &LO) { |
187 | return true; |
188 | } |
189 | |