blob: 04d77bc31e85018c950d8eecf6957c5dc9fd5c74 [file] [log] [blame]
Zhongxing Xu259d4642009-11-04 01:43:07 +00001//=== VLASizeChecker.cpp - Undefined dereference checker --------*- C++ -*-===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Zhongxing Xu259d4642009-11-04 01:43:07 +00006//
7//===----------------------------------------------------------------------===//
8//
Ted Kremenek3a0678e2015-09-08 03:50:52 +00009// This defines VLASizeChecker, a builtin check in ExprEngine that
Zhongxing Xu259d4642009-11-04 01:43:07 +000010// performs checks for declaration of VLA of undefined or zero size.
Jordy Rosecf781e52010-07-06 23:33:54 +000011// In addition, VLASizeChecker is responsible for defining the extent
12// of the MemRegion that represents a VLA.
Zhongxing Xu259d4642009-11-04 01:43:07 +000013//
14//===----------------------------------------------------------------------===//
15
Kristof Umann76a21502018-12-15 16:23:51 +000016#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
Chandler Carruth3a022472012-12-04 09:13:33 +000017#include "clang/AST/CharUnits.h"
18#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +000019#include "clang/StaticAnalyzer/Core/Checker.h"
Argyrios Kyrtzidis68ed6252011-02-28 01:27:54 +000020#include "clang/StaticAnalyzer/Core/CheckerManager.h"
21#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
Benjamin Kramer3307c5082012-02-04 12:31:12 +000022#include "llvm/ADT/STLExtras.h"
Chandler Carruth3a022472012-12-04 09:13:33 +000023#include "llvm/ADT/SmallString.h"
Benjamin Kramer444a1302012-12-01 17:12:56 +000024#include "llvm/Support/raw_ostream.h"
Zhongxing Xu259d4642009-11-04 01:43:07 +000025
26using namespace clang;
Ted Kremenek98857c92010-12-23 07:20:52 +000027using namespace ento;
Zhongxing Xu259d4642009-11-04 01:43:07 +000028
Ted Kremenek795c6112009-11-06 21:51:50 +000029namespace {
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +000030class VLASizeChecker : public Checker< check::PreStmt<DeclStmt> > {
Ahmed Charlesb8984322014-03-07 20:03:18 +000031 mutable std::unique_ptr<BugType> BT;
Jordan Rose1a9c0d12014-08-12 16:44:22 +000032 enum VLASize_Kind { VLA_Garbage, VLA_Zero, VLA_Tainted, VLA_Negative };
Anna Zaksb7eac9f2012-01-21 05:07:33 +000033
Henry Wonge14e5912018-05-02 12:11:22 +000034 void reportBug(VLASize_Kind Kind, const Expr *SizeE, ProgramStateRef State,
35 CheckerContext &C,
36 std::unique_ptr<BugReporterVisitor> Visitor = nullptr) const;
37
Ted Kremenek795c6112009-11-06 21:51:50 +000038public:
Argyrios Kyrtzidis68ed6252011-02-28 01:27:54 +000039 void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const;
Ted Kremenek795c6112009-11-06 21:51:50 +000040};
41} // end anonymous namespace
42
Henry Wonge14e5912018-05-02 12:11:22 +000043void VLASizeChecker::reportBug(
44 VLASize_Kind Kind, const Expr *SizeE, ProgramStateRef State,
45 CheckerContext &C, std::unique_ptr<BugReporterVisitor> Visitor) const {
Anna Zaksb7eac9f2012-01-21 05:07:33 +000046 // Generate an error node.
Devin Coughline39bd402015-09-16 22:03:05 +000047 ExplodedNode *N = C.generateErrorNode(State);
Anna Zaksb7eac9f2012-01-21 05:07:33 +000048 if (!N)
49 return;
50
51 if (!BT)
Alexander Kornienko4aca9b12014-02-11 21:49:21 +000052 BT.reset(new BuiltinBug(
53 this, "Dangerous variable-length array (VLA) declaration"));
Anna Zaksb7eac9f2012-01-21 05:07:33 +000054
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +000055 SmallString<256> buf;
Anna Zaksb7eac9f2012-01-21 05:07:33 +000056 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;
Jordan Rose1a9c0d12014-08-12 16:44:22 +000068 case VLA_Negative:
69 os << "has negative size";
70 break;
Anna Zaksb7eac9f2012-01-21 05:07:33 +000071 }
72
Aaron Ballman8d3a7a52015-06-23 13:15:32 +000073 auto report = llvm::make_unique<BugReport>(*BT, os.str(), N);
Henry Wonge14e5912018-05-02 12:11:22 +000074 report->addVisitor(std::move(Visitor));
Anna Zaksb7eac9f2012-01-21 05:07:33 +000075 report->addRange(SizeE->getSourceRange());
George Karpenkovb2cf0062018-10-23 18:24:53 +000076 bugreporter::trackExpressionValue(N, SizeE, *report);
Aaron Ballman8d3a7a52015-06-23 13:15:32 +000077 C.emitReport(std::move(report));
Anna Zaksb7eac9f2012-01-21 05:07:33 +000078}
79
Argyrios Kyrtzidis68ed6252011-02-28 01:27:54 +000080void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
Ted Kremenekae3361d2009-11-07 03:56:57 +000081 if (!DS->isSingleDecl())
82 return;
Ted Kremenek3a0678e2015-09-08 03:50:52 +000083
Ted Kremenekae3361d2009-11-07 03:56:57 +000084 const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
85 if (!VD)
86 return;
Jordy Rosee6b999b2010-07-05 00:50:15 +000087
88 ASTContext &Ctx = C.getASTContext();
89 const VariableArrayType *VLA = Ctx.getAsVariableArrayType(VD->getType());
Ted Kremenekae3361d2009-11-07 03:56:57 +000090 if (!VLA)
91 return;
Zhongxing Xu259d4642009-11-04 01:43:07 +000092
Ted Kremenekae3361d2009-11-07 03:56:57 +000093 // FIXME: Handle multi-dimensional VLAs.
Ted Kremenek5ef32db2011-08-12 23:37:29 +000094 const Expr *SE = VLA->getSizeExpr();
Ted Kremenek49b1e382012-01-26 21:29:00 +000095 ProgramStateRef state = C.getState();
George Karpenkovd703ec92018-01-17 20:27:29 +000096 SVal sizeV = C.getSVal(SE);
Zhongxing Xu259d4642009-11-04 01:43:07 +000097
Ted Kremenekae3361d2009-11-07 03:56:57 +000098 if (sizeV.isUndef()) {
Anna Zaksb7eac9f2012-01-21 05:07:33 +000099 reportBug(VLA_Garbage, SE, state, C);
Ted Kremenekae3361d2009-11-07 03:56:57 +0000100 return;
Zhongxing Xu259d4642009-11-04 01:43:07 +0000101 }
Jordy Rosee6b999b2010-07-05 00:50:15 +0000102
103 // See if the size value is known. It can't be undefined because we would have
104 // warned about that already.
105 if (sizeV.isUnknown())
106 return;
Ted Kremenek3a0678e2015-09-08 03:50:52 +0000107
Anna Zaksb7eac9f2012-01-21 05:07:33 +0000108 // Check if the size is tainted.
109 if (state->isTainted(sizeV)) {
Henry Wonge14e5912018-05-02 12:11:22 +0000110 reportBug(VLA_Tainted, SE, nullptr, C,
111 llvm::make_unique<TaintBugVisitor>(sizeV));
Anna Zaksb7eac9f2012-01-21 05:07:33 +0000112 return;
113 }
114
Ted Kremenekae3361d2009-11-07 03:56:57 +0000115 // Check if the size is zero.
David Blaikie2fdacbc2013-02-20 05:52:05 +0000116 DefinedSVal sizeD = sizeV.castAs<DefinedSVal>();
Zhongxing Xu259d4642009-11-04 01:43:07 +0000117
Ted Kremenek49b1e382012-01-26 21:29:00 +0000118 ProgramStateRef stateNotZero, stateZero;
Benjamin Kramer867ea1d2014-03-02 13:01:17 +0000119 std::tie(stateNotZero, stateZero) = state->assume(sizeD);
Zhongxing Xu259d4642009-11-04 01:43:07 +0000120
Ted Kremenekae3361d2009-11-07 03:56:57 +0000121 if (stateZero && !stateNotZero) {
Anna Zaksb7eac9f2012-01-21 05:07:33 +0000122 reportBug(VLA_Zero, SE, stateZero, C);
Ted Kremenekae3361d2009-11-07 03:56:57 +0000123 return;
Zhongxing Xu259d4642009-11-04 01:43:07 +0000124 }
Ted Kremenek3a0678e2015-09-08 03:50:52 +0000125
Ted Kremenekae3361d2009-11-07 03:56:57 +0000126 // From this point on, assume that the size is not zero.
Jordy Rosee6b999b2010-07-05 00:50:15 +0000127 state = stateNotZero;
128
Jordy Rosecf781e52010-07-06 23:33:54 +0000129 // VLASizeChecker is responsible for defining the extent of the array being
130 // declared. We do this by multiplying the array length by the element size,
131 // then matching that with the array region's extent symbol.
132
Jordan Rose1a9c0d12014-08-12 16:44:22 +0000133 // Check if the size is negative.
Ted Kremenek90af9092010-12-02 07:49:45 +0000134 SValBuilder &svalBuilder = C.getSValBuilder();
Jordan Rose1a9c0d12014-08-12 16:44:22 +0000135
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 // Convert the array length to size_t.
Jordy Rosee6b999b2010-07-05 00:50:15 +0000154 QualType SizeTy = Ctx.getSizeType();
David Blaikie2fdacbc2013-02-20 05:52:05 +0000155 NonLoc ArrayLength =
156 svalBuilder.evalCast(sizeD, SizeTy, SE->getType()).castAs<NonLoc>();
Jordy Rosee6b999b2010-07-05 00:50:15 +0000157
158 // Get the element size.
159 CharUnits EleSize = Ctx.getTypeSizeInChars(VLA->getElementType());
Ted Kremenek90af9092010-12-02 07:49:45 +0000160 SVal EleSizeVal = svalBuilder.makeIntVal(EleSize.getQuantity(), SizeTy);
Jordy Rosee6b999b2010-07-05 00:50:15 +0000161
162 // Multiply the array length by the element size.
David Blaikie2fdacbc2013-02-20 05:52:05 +0000163 SVal ArraySizeVal = svalBuilder.evalBinOpNN(
164 state, BO_Mul, ArrayLength, EleSizeVal.castAs<NonLoc>(), SizeTy);
Jordy Rosee6b999b2010-07-05 00:50:15 +0000165
Ted Kremenekc5bea1e2010-12-01 22:16:56 +0000166 // Finally, assume that the array's extent matches the given size.
Anna Zaksc9abbe22011-10-26 21:06:44 +0000167 const LocationContext *LC = C.getLocationContext();
Ted Kremenek90af9092010-12-02 07:49:45 +0000168 DefinedOrUnknownSVal Extent =
169 state->getRegion(VD, LC)->getExtent(svalBuilder);
David Blaikie2fdacbc2013-02-20 05:52:05 +0000170 DefinedOrUnknownSVal ArraySize = ArraySizeVal.castAs<DefinedOrUnknownSVal>();
Ted Kremenek90af9092010-12-02 07:49:45 +0000171 DefinedOrUnknownSVal sizeIsKnown =
172 svalBuilder.evalEQ(state, Extent, ArraySize);
173 state = state->assume(sizeIsKnown, true);
Jordy Rosee6b999b2010-07-05 00:50:15 +0000174
Zhongxing Xu5b488b12010-07-06 07:08:47 +0000175 // Assume should not fail at this point.
176 assert(state);
177
Jordy Rosee6b999b2010-07-05 00:50:15 +0000178 // Remember our assumptions!
Anna Zaksda4c8d62011-10-26 21:06:34 +0000179 C.addTransition(state);
Zhongxing Xu259d4642009-11-04 01:43:07 +0000180}
Argyrios Kyrtzidis68ed6252011-02-28 01:27:54 +0000181
182void ento::registerVLASizeChecker(CheckerManager &mgr) {
183 mgr.registerChecker<VLASizeChecker>();
184}
Kristof Umann058a7a42019-01-26 14:23:08 +0000185
186bool ento::shouldRegisterVLASizeChecker(const LangOptions &LO) {
187 return true;
188}