Source code

Revision control

Other Tools

1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
* License, v. 2.0. If a copy of the MPL was not distributed with this
3
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
#include "ScopeChecker.h"
6
#include "CustomMatchers.h"
7
8
void ScopeChecker::registerMatchers(MatchFinder *AstMatcher) {
9
AstMatcher->addMatcher(varDecl().bind("node"), this);
10
AstMatcher->addMatcher(cxxNewExpr().bind("node"), this);
11
AstMatcher->addMatcher(
12
materializeTemporaryExpr(
13
unless(hasDescendant(cxxConstructExpr(allowsTemporary())))
14
).bind("node"), this);
15
AstMatcher->addMatcher(
16
callExpr(callee(functionDecl(heapAllocator()))).bind("node"), this);
17
}
18
19
// These enum variants determine whether an allocation has occured in the code.
20
enum AllocationVariety {
21
AV_None,
22
AV_Global,
23
AV_Automatic,
24
AV_Temporary,
25
AV_Heap,
26
};
27
28
// XXX Currently the Decl* in the AutomaticTemporaryMap is unused, but it
29
// probably will be used at some point in the future, in order to produce better
30
// error messages.
31
typedef DenseMap<const MaterializeTemporaryExpr *, const Decl *>
32
AutomaticTemporaryMap;
33
AutomaticTemporaryMap AutomaticTemporaries;
34
35
void ScopeChecker::check(const MatchFinder::MatchResult &Result) {
36
// There are a variety of different reasons why something could be allocated
37
AllocationVariety Variety = AV_None;
38
SourceLocation Loc;
39
QualType T;
40
bool IsStaticLocal = false;
41
42
if (const ParmVarDecl *D =
43
Result.Nodes.getNodeAs<ParmVarDecl>("node")) {
44
if (D->hasUnparsedDefaultArg() || D->hasUninstantiatedDefaultArg()) {
45
return;
46
}
47
if (const Expr *Default = D->getDefaultArg()) {
48
if (const MaterializeTemporaryExpr *E =
49
dyn_cast<MaterializeTemporaryExpr>(Default)) {
50
// We have just found a ParmVarDecl which has, as its default argument,
51
// a MaterializeTemporaryExpr. We mark that MaterializeTemporaryExpr as
52
// automatic, by adding it to the AutomaticTemporaryMap.
53
// Reporting on this type will occur when the MaterializeTemporaryExpr
54
// is matched against.
55
AutomaticTemporaries[E] = D;
56
}
57
}
58
return;
59
}
60
61
// Determine the type of allocation which we detected
62
if (const VarDecl *D = Result.Nodes.getNodeAs<VarDecl>("node")) {
63
if (D->hasGlobalStorage()) {
64
Variety = AV_Global;
65
} else {
66
Variety = AV_Automatic;
67
}
68
T = D->getType();
69
Loc = D->getBeginLoc();
70
IsStaticLocal = D->isStaticLocal();
71
} else if (const CXXNewExpr *E = Result.Nodes.getNodeAs<CXXNewExpr>("node")) {
72
// New allocates things on the heap.
73
// We don't consider placement new to do anything, as it doesn't actually
74
// allocate the storage, and thus gives us no useful information.
75
if (!isPlacementNew(E)) {
76
Variety = AV_Heap;
77
T = E->getAllocatedType();
78
Loc = E->getBeginLoc();
79
}
80
} else if (const MaterializeTemporaryExpr *E =
81
Result.Nodes.getNodeAs<MaterializeTemporaryExpr>("node")) {
82
// Temporaries can actually have varying storage durations, due to temporary
83
// lifetime extension. We consider the allocation variety of this temporary
84
// to be the same as the allocation variety of its lifetime.
85
86
// XXX We maybe should mark these lifetimes as being due to a temporary
87
// which has had its lifetime extended, to improve the error messages.
88
switch (E->getStorageDuration()) {
89
case SD_FullExpression: {
90
// Check if this temporary is allocated as a default argument!
91
// if it is, we want to pretend that it is automatic.
92
AutomaticTemporaryMap::iterator AutomaticTemporary =
93
AutomaticTemporaries.find(E);
94
if (AutomaticTemporary != AutomaticTemporaries.end()) {
95
Variety = AV_Automatic;
96
} else {
97
Variety = AV_Temporary;
98
}
99
} break;
100
case SD_Automatic:
101
Variety = AV_Automatic;
102
break;
103
case SD_Thread:
104
case SD_Static:
105
Variety = AV_Global;
106
break;
107
case SD_Dynamic:
108
assert(false && "I don't think that this ever should occur...");
109
Variety = AV_Heap;
110
break;
111
}
112
T = E->getType().getUnqualifiedType();
113
Loc = E->getBeginLoc();
114
} else if (const CallExpr *E = Result.Nodes.getNodeAs<CallExpr>("node")) {
115
T = E->getType()->getPointeeType();
116
if (!T.isNull()) {
117
// This will always allocate on the heap, as the heapAllocator() check
118
// was made in the matcher
119
Variety = AV_Heap;
120
Loc = E->getBeginLoc();
121
}
122
}
123
124
// Error messages for incorrect allocations.
125
const char *Stack = "variable of type %0 only valid on the stack";
126
const char *Global = "variable of type %0 only valid as global";
127
const char *Heap = "variable of type %0 only valid on the heap";
128
const char *NonHeap = "variable of type %0 is not valid on the heap";
129
const char *NonTemporary = "variable of type %0 is not valid in a temporary";
130
const char *Temporary = "variable of type %0 is only valid as a temporary";
131
const char *StaticLocal = "variable of type %0 is only valid as a static "
132
"local";
133
134
const char *StackNote =
135
"value incorrectly allocated in an automatic variable";
136
const char *GlobalNote = "value incorrectly allocated in a global variable";
137
const char *HeapNote = "value incorrectly allocated on the heap";
138
const char *TemporaryNote = "value incorrectly allocated in a temporary";
139
140
// Report errors depending on the annotations on the input types.
141
switch (Variety) {
142
case AV_None:
143
return;
144
145
case AV_Global:
146
StackClass.reportErrorIfPresent(*this, T, Loc, Stack, GlobalNote);
147
HeapClass.reportErrorIfPresent(*this, T, Loc, Heap, GlobalNote);
148
TemporaryClass.reportErrorIfPresent(*this, T, Loc, Temporary, GlobalNote);
149
if (!IsStaticLocal) {
150
StaticLocalClass.reportErrorIfPresent(*this, T, Loc, StaticLocal,
151
GlobalNote);
152
}
153
break;
154
155
case AV_Automatic:
156
GlobalClass.reportErrorIfPresent(*this, T, Loc, Global, StackNote);
157
HeapClass.reportErrorIfPresent(*this, T, Loc, Heap, StackNote);
158
TemporaryClass.reportErrorIfPresent(*this, T, Loc, Temporary, StackNote);
159
StaticLocalClass.reportErrorIfPresent(*this, T, Loc, StaticLocal,
160
StackNote);
161
break;
162
163
case AV_Temporary:
164
GlobalClass.reportErrorIfPresent(*this, T, Loc, Global, TemporaryNote);
165
HeapClass.reportErrorIfPresent(*this, T, Loc, Heap, TemporaryNote);
166
NonTemporaryClass.reportErrorIfPresent(*this, T, Loc, NonTemporary,
167
TemporaryNote);
168
StaticLocalClass.reportErrorIfPresent(*this, T, Loc, StaticLocal,
169
TemporaryNote);
170
break;
171
172
case AV_Heap:
173
GlobalClass.reportErrorIfPresent(*this, T, Loc, Global, HeapNote);
174
StackClass.reportErrorIfPresent(*this, T, Loc, Stack, HeapNote);
175
NonHeapClass.reportErrorIfPresent(*this, T, Loc, NonHeap, HeapNote);
176
TemporaryClass.reportErrorIfPresent(*this, T, Loc, Temporary, HeapNote);
177
StaticLocalClass.reportErrorIfPresent(*this, T, Loc, StaticLocal, HeapNote);
178
break;
179
}
180
}