clang: lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
22
23using namespace clang;
24using namespace ento;
25
26
29
30
31namespace {
32
33class InnerPointerChecker
34 : public Checker<check::DeadSymbols, check::PostCall> {
35
36 CallDescriptionSet InvalidatingMemberFunctions{
37 CallDescription(CDM::CXXMethod, {"std", "basic_string", "append"}),
38 CallDescription(CDM::CXXMethod, {"std", "basic_string", "assign"}),
39 CallDescription(CDM::CXXMethod, {"std", "basic_string", "clear"}),
40 CallDescription(CDM::CXXMethod, {"std", "basic_string", "erase"}),
41 CallDescription(CDM::CXXMethod, {"std", "basic_string", "insert"}),
42 CallDescription(CDM::CXXMethod, {"std", "basic_string", "pop_back"}),
43 CallDescription(CDM::CXXMethod, {"std", "basic_string", "push_back"}),
44 CallDescription(CDM::CXXMethod, {"std", "basic_string", "replace"}),
45 CallDescription(CDM::CXXMethod, {"std", "basic_string", "reserve"}),
46 CallDescription(CDM::CXXMethod, {"std", "basic_string", "resize"}),
47 CallDescription(CDM::CXXMethod, {"std", "basic_string", "shrink_to_fit"}),
48 CallDescription(CDM::CXXMethod, {"std", "basic_string", "swap"})};
49
50 CallDescriptionSet AddressofFunctions{
51 CallDescription(CDM::SimpleFunc, {"std", "addressof"}),
52 CallDescription(CDM::SimpleFunc, {"std", "__addressof"})};
53
54 CallDescriptionSet InnerPointerAccessFunctions{
55 CallDescription(CDM::CXXMethod, {"std", "basic_string", "c_str"}),
56 CallDescription(CDM::SimpleFunc, {"std", "data"}, 1),
57 CallDescription(CDM::CXXMethod, {"std", "basic_string", "data"})};
58
59public:
60 class InnerPointerBRVisitor : public BugReporterVisitor {
62
63 public:
64 InnerPointerBRVisitor(SymbolRef Sym) : PtrToBuf(Sym) {}
65
66 static void *getTag() {
67 static int Tag = 0;
68 return &Tag;
69 }
70
71 void Profile(llvm::FoldingSetNodeID &ID) const override {
72 ID.AddPointer(getTag());
73 }
74
76 BugReporterContext &BRC,
77 PathSensitiveBugReport &BR) override;
78
79
80
82 RawPtrMapTy Map = State->get();
83 for (const auto &Entry : Map) {
84 if (Entry.second.contains(Sym))
85 return true;
86 }
87 return false;
88 }
89 };
90
91
92
93 bool isInvalidatingMemberFunction(const CallEvent &Call) const;
94
95
96
98 const MemRegion *ObjRegion,
99 CheckerContext &C) const;
100
101
102
103
104 void checkFunctionArguments(const CallEvent &Call, ProgramStateRef State,
105 CheckerContext &C) const;
106
107
108
109
110 void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
111
112
113 void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
114};
115
116}
117
118bool InnerPointerChecker::isInvalidatingMemberFunction(
120 if (const auto *MemOpCall = dyn_cast(&Call)) {
122 if (Opc == OO_Equal || Opc == OO_PlusEqual)
123 return true;
124 return false;
125 }
128}
129
130void InnerPointerChecker::markPtrSymbolsReleased(const CallEvent &Call,
132 const MemRegion *MR,
133 CheckerContext &C) const {
134 if (const PtrSet *PS = State->get(MR)) {
135 const Expr *Origin = Call.getOriginExpr();
136 for (const auto Symbol : *PS) {
137
138
140 }
141 State = State->remove(MR);
142 C.addTransition(State);
143 return;
144 }
145}
146
147void InnerPointerChecker::checkFunctionArguments(const CallEvent &Call,
149 CheckerContext &C) const {
150 if (const auto *FC = dyn_cast(&Call)) {
151 const FunctionDecl *FD = FC->getDecl();
153 return;
154
155 for (unsigned I = 0, E = FD->getNumParams(); I != E; ++I) {
159 continue;
160
161
162
164 unsigned ArgI = isaMemberOpCall ? I+1 : I;
165
166 SVal Arg = FC->getArgSVal(ArgI);
167 const auto *ArgRegion =
168 dyn_cast_or_null(Arg.getAsRegion());
169 if (!ArgRegion)
170 continue;
171
172
173
175 continue;
176
177 markPtrSymbolsReleased(Call, State, ArgRegion, C);
178 }
179 }
180}
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196void InnerPointerChecker::checkPostCall(const CallEvent &Call,
197 CheckerContext &C) const {
199
200
201 const TypedValueRegion *ObjRegion = nullptr;
202
203 if (const auto *ICall = dyn_cast(&Call)) {
204 ObjRegion = dyn_cast_or_null(
205 ICall->getCXXThisVal().getAsRegion());
206
207
208 if (isInvalidatingMemberFunction(Call)) {
209 markPtrSymbolsReleased(Call, State, ObjRegion, C);
210 return;
211 }
212 }
213
214 if (InnerPointerAccessFunctions.contains(Call)) {
215
217
218
219
220 ObjRegion =
221 dyn_cast_or_null(Call.getArgSVal(0).getAsRegion());
222 }
223
224 if (!ObjRegion)
225 return;
226
227 SVal RawPtr = Call.getReturnValue();
229
230
231
232 PtrSet::Factory &F = State->getStateManager().get_context();
233 const PtrSet *SetPtr = State->get(ObjRegion);
234 PtrSet Set = SetPtr ? *SetPtr : F.getEmptySet();
235 assert(C.wasInlined || .contains(Sym));
237
238 State = State->set(ObjRegion, Set);
239 C.addTransition(State);
240 }
241
242 return;
243 }
244
245
246 checkFunctionArguments(Call, State, C);
247}
248
249void InnerPointerChecker::checkDeadSymbols(SymbolReaper &SymReaper,
250 CheckerContext &C) const {
252 PtrSet::Factory &F = State->getStateManager().get_context();
253 RawPtrMapTy RPM = State->get();
254 for (const auto &Entry : RPM) {
256
257
258 State = State->remove(Entry.first);
259 }
260 if (const PtrSet *OldSet = State->get(Entry.first)) {
261 PtrSet CleanedUpSet = *OldSet;
262 for (const auto Symbol : Entry.second) {
263 if (!SymReaper.isLive(Symbol))
264 CleanedUpSet = F.remove(CleanedUpSet, Symbol);
265 }
266 State = CleanedUpSet.isEmpty()
267 ? State->remove(Entry.first)
268 : State->set(Entry.first, CleanedUpSet);
269 }
270 }
271 C.addTransition(State);
272}
273
274namespace clang {
275namespace ento {
276namespace allocation_state {
277
279 return std::make_uniqueInnerPointerChecker::InnerPointerBRVisitor(Sym);
280}
281
283 RawPtrMapTy Map = State->get();
284 for (const auto &Entry : Map) {
285 if (Entry.second.contains(Sym)) {
286 return Entry.first;
287 }
288 }
289 return nullptr;
290}
291
292}
293}
294}
295
297 const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &) {
298 if (!isSymbolTracked(N->getState(), PtrToBuf) ||
300 return nullptr;
301
303 if (!S)
304 return nullptr;
305
306 const MemRegion *ObjRegion =
309 QualType ObjTy = TypedRegion->getValueType();
310
311 SmallString<256> Buf;
312 llvm::raw_svector_ostream OS(Buf);
313 OS << "Pointer to inner buffer of '" << ObjTy << "' obtained here";
316 return std::make_shared(Pos, OS.str(), true);
317}
318
319void ento::registerInnerPointerChecker(CheckerManager &Mgr) {
322}
323
324bool ento::shouldRegisterInnerPointerChecker(const CheckerManager &mgr) {
325 return true;
326}
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
#define REGISTER_SET_FACTORY_WITH_PROGRAMSTATE(Name, Elem)
Declares an immutable set type Name and registers the factory for such sets in the program state,...
bool isInStdNamespace() const
const ParmVarDecl * getParamDecl(unsigned i) const
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
bool isConstQualified() const
Determine whether this type is const-qualified.
bool isReferenceType() const
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
const SourceManager & getSourceManager() const
bool contains(const CallEvent &Call) const
Represents an abstract call to a function or method along a particular path.
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
Simple checker classes that implement one frontend (i.e.
const ProgramStateRef & getState() const
const Stmt * getStmtForDiagnostics() const
If the node's program point corresponds to a statement, retrieve that statement.
const LocationContext * getLocationContext() const
ExplodedNode * getFirstPred()
MemRegion - The root abstract class for all memory regions.
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
const MemRegion * getAsRegion() const
bool isLiveRegion(const MemRegion *region)
bool isLive(SymbolRef sym)
ProgramStateRef markReleased(ProgramStateRef State, SymbolRef Sym, const Expr *Origin)
std::unique_ptr< BugReporterVisitor > getInnerPointerBRVisitor(SymbolRef Sym)
This function provides an additional visitor that augments the bug report with information relevant t...
Definition InnerPointerChecker.cpp:278
const MemRegion * getContainerObjRegion(ProgramStateRef State, SymbolRef Sym)
'Sym' represents a pointer to the inner buffer of a container object.
Definition InnerPointerChecker.cpp:282
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const SymExpr * SymbolRef
void registerInnerPointerCheckerAux(CheckerManager &Mgr)
Register the part of MallocChecker connected to InnerPointerChecker.
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
The JSON file list parser is used to communicate input to InstallAPI.
OverloadedOperatorKind
Enumeration specifying the different kinds of C++ overloaded operators.
bool isa(CodeGen::Address addr)
U cast(CodeGen::Address addr)