1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" |
24 | #include "clang/AST/ParentMap.h" |
25 | #include "clang/AST/RecursiveASTVisitor.h" |
26 | #include "clang/Basic/Builtins.h" |
27 | #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" |
28 | #include "clang/StaticAnalyzer/Core/Checker.h" |
29 | #include "clang/StaticAnalyzer/Core/CheckerManager.h" |
30 | #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" |
31 | #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h" |
32 | #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" |
33 | #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" |
34 | |
35 | using namespace clang; |
36 | using namespace ento; |
37 | |
38 | |
39 | |
40 | |
41 | |
42 | |
43 | |
44 | |
45 | |
46 | REGISTER_MAP_WITH_PROGRAMSTATE(MostSpecializedTypeArgsMap, SymbolRef, |
47 | const ObjCObjectPointerType *) |
48 | |
49 | namespace { |
50 | class DynamicTypePropagation: |
51 | public Checker< check::PreCall, |
52 | check::PostCall, |
53 | check::DeadSymbols, |
54 | check::PostStmt<CastExpr>, |
55 | check::PostStmt<CXXNewExpr>, |
56 | check::PreObjCMessage, |
57 | check::PostObjCMessage > { |
58 | const ObjCObjectType *getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE, |
59 | CheckerContext &C) const; |
60 | |
61 | |
62 | const ObjCObjectPointerType *getBetterObjCType(const Expr *CastE, |
63 | CheckerContext &C) const; |
64 | |
65 | ExplodedNode *dynamicTypePropagationOnCasts(const CastExpr *CE, |
66 | ProgramStateRef &State, |
67 | CheckerContext &C) const; |
68 | |
69 | mutable std::unique_ptr<BugType> ObjCGenericsBugType; |
70 | void initBugType() const { |
71 | if (!ObjCGenericsBugType) |
72 | ObjCGenericsBugType.reset( |
73 | new BugType(this, "Generics", categories::CoreFoundationObjectiveC)); |
74 | } |
75 | |
76 | class GenericsBugVisitor : public BugReporterVisitor { |
77 | public: |
78 | GenericsBugVisitor(SymbolRef S) : Sym(S) {} |
79 | |
80 | void Profile(llvm::FoldingSetNodeID &ID) const override { |
81 | static int X = 0; |
82 | ID.AddPointer(&X); |
83 | ID.AddPointer(Sym); |
84 | } |
85 | |
86 | std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N, |
87 | BugReporterContext &BRC, |
88 | BugReport &BR) override; |
89 | |
90 | private: |
91 | |
92 | SymbolRef Sym; |
93 | }; |
94 | |
95 | void reportGenericsBug(const ObjCObjectPointerType *From, |
96 | const ObjCObjectPointerType *To, ExplodedNode *N, |
97 | SymbolRef Sym, CheckerContext &C, |
98 | const Stmt *ReportedNode = nullptr) const; |
99 | |
100 | public: |
101 | void checkPreCall(const CallEvent &Call, CheckerContext &C) const; |
102 | void checkPostCall(const CallEvent &Call, CheckerContext &C) const; |
103 | void checkPostStmt(const CastExpr *CastE, CheckerContext &C) const; |
104 | void checkPostStmt(const CXXNewExpr *NewE, CheckerContext &C) const; |
105 | void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const; |
106 | void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const; |
107 | void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const; |
108 | |
109 | |
110 | DefaultBool CheckGenerics; |
111 | }; |
112 | } |
113 | |
114 | void DynamicTypePropagation::checkDeadSymbols(SymbolReaper &SR, |
115 | CheckerContext &C) const { |
116 | ProgramStateRef State = C.getState(); |
117 | DynamicTypeMapImpl TypeMap = State->get<DynamicTypeMap>(); |
118 | for (DynamicTypeMapImpl::iterator I = TypeMap.begin(), E = TypeMap.end(); |
119 | I != E; ++I) { |
120 | if (!SR.isLiveRegion(I->first)) { |
121 | State = State->remove<DynamicTypeMap>(I->first); |
122 | } |
123 | } |
124 | |
125 | MostSpecializedTypeArgsMapTy TyArgMap = |
126 | State->get<MostSpecializedTypeArgsMap>(); |
127 | for (MostSpecializedTypeArgsMapTy::iterator I = TyArgMap.begin(), |
128 | E = TyArgMap.end(); |
129 | I != E; ++I) { |
130 | if (SR.isDead(I->first)) { |
131 | State = State->remove<MostSpecializedTypeArgsMap>(I->first); |
132 | } |
133 | } |
134 | |
135 | C.addTransition(State); |
136 | } |
137 | |
138 | static void recordFixedType(const MemRegion *Region, const CXXMethodDecl *MD, |
139 | CheckerContext &C) { |
140 | assert(Region); |
141 | assert(MD); |
142 | |
143 | ASTContext &Ctx = C.getASTContext(); |
144 | QualType Ty = Ctx.getPointerType(Ctx.getRecordType(MD->getParent())); |
145 | |
146 | ProgramStateRef State = C.getState(); |
147 | State = setDynamicTypeInfo(State, Region, Ty, ); |
148 | C.addTransition(State); |
149 | } |
150 | |
151 | void DynamicTypePropagation::checkPreCall(const CallEvent &Call, |
152 | CheckerContext &C) const { |
153 | if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) { |
154 | |
155 | |
156 | |
157 | |
158 | |
159 | |
160 | |
161 | |
162 | switch (Ctor->getOriginExpr()->getConstructionKind()) { |
163 | case CXXConstructExpr::CK_Complete: |
164 | case CXXConstructExpr::CK_Delegating: |
165 | |
166 | return; |
167 | case CXXConstructExpr::CK_NonVirtualBase: |
168 | case CXXConstructExpr::CK_VirtualBase: |
169 | if (const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion()) |
170 | recordFixedType(Target, Ctor->getDecl(), C); |
171 | return; |
172 | } |
173 | |
174 | return; |
175 | } |
176 | |
177 | if (const CXXDestructorCall *Dtor = dyn_cast<CXXDestructorCall>(&Call)) { |
178 | |
179 | if (!Dtor->isBaseDestructor()) |
180 | return; |
181 | |
182 | const MemRegion *Target = Dtor->getCXXThisVal().getAsRegion(); |
183 | if (!Target) |
184 | return; |
185 | |
186 | const Decl *D = Dtor->getDecl(); |
187 | if (!D) |
188 | return; |
189 | |
190 | recordFixedType(Target, cast<CXXDestructorDecl>(D), C); |
191 | return; |
192 | } |
193 | } |
194 | |
195 | void DynamicTypePropagation::checkPostCall(const CallEvent &Call, |
196 | CheckerContext &C) const { |
197 | |
198 | if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(&Call)) { |
199 | |
200 | |
201 | const MemRegion *RetReg = Call.getReturnValue().getAsRegion(); |
202 | if (!RetReg) |
203 | return; |
204 | |
205 | ProgramStateRef State = C.getState(); |
206 | const ObjCMethodDecl *D = Msg->getDecl(); |
207 | |
208 | if (D && D->hasRelatedResultType()) { |
209 | switch (Msg->getMethodFamily()) { |
210 | default: |
211 | break; |
212 | |
213 | |
214 | |
215 | |
216 | case OMF_alloc: |
217 | case OMF_new: { |
218 | |
219 | const ObjCMessageExpr *MsgE = Msg->getOriginExpr(); |
220 | const ObjCObjectType *ObjTy = getObjectTypeForAllocAndNew(MsgE, C); |
221 | if (!ObjTy) |
222 | return; |
223 | QualType DynResTy = |
224 | C.getASTContext().getObjCObjectPointerType(QualType(ObjTy, 0)); |
225 | C.addTransition(setDynamicTypeInfo(State, RetReg, DynResTy, false)); |
226 | break; |
227 | } |
228 | case OMF_init: { |
229 | |
230 | |
231 | const MemRegion *RecReg = Msg->getReceiverSVal().getAsRegion(); |
232 | if (!RecReg) |
233 | return; |
234 | DynamicTypeInfo RecDynType = getDynamicTypeInfo(State, RecReg); |
235 | C.addTransition(setDynamicTypeInfo(State, RetReg, RecDynType)); |
236 | break; |
237 | } |
238 | } |
239 | } |
240 | return; |
241 | } |
242 | |
243 | if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) { |
244 | |
245 | switch (Ctor->getOriginExpr()->getConstructionKind()) { |
246 | case CXXConstructExpr::CK_Complete: |
247 | case CXXConstructExpr::CK_Delegating: |
248 | |
249 | |
250 | |
251 | |
252 | |
253 | return; |
254 | case CXXConstructExpr::CK_NonVirtualBase: |
255 | case CXXConstructExpr::CK_VirtualBase: |
256 | if (const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion()) { |
257 | |
258 | |
259 | const LocationContext *LCtx = C.getLocationContext(); |
260 | |
261 | |
262 | |
263 | |
264 | |
265 | |
266 | |
267 | if (dyn_cast_or_null<InitListExpr>( |
268 | LCtx->getParentMap().getParent(Ctor->getOriginExpr()))) |
269 | return; |
270 | |
271 | recordFixedType(Target, cast<CXXConstructorDecl>(LCtx->getDecl()), C); |
272 | } |
273 | return; |
274 | } |
275 | } |
276 | } |
277 | |
278 | |
279 | |
280 | |
281 | |
282 | ExplodedNode *DynamicTypePropagation::dynamicTypePropagationOnCasts( |
283 | const CastExpr *CE, ProgramStateRef &State, CheckerContext &C) const { |
284 | |
285 | const MemRegion *ToR = C.getSVal(CE).getAsRegion(); |
286 | if (!ToR) |
287 | return C.getPredecessor(); |
288 | |
289 | if (isa<ExplicitCastExpr>(CE)) |
290 | return C.getPredecessor(); |
291 | |
292 | if (const Type *NewTy = getBetterObjCType(CE, C)) { |
293 | State = setDynamicTypeInfo(State, ToR, QualType(NewTy, 0)); |
294 | return C.addTransition(State); |
295 | } |
296 | return C.getPredecessor(); |
297 | } |
298 | |
299 | void DynamicTypePropagation::checkPostStmt(const CXXNewExpr *NewE, |
300 | CheckerContext &C) const { |
301 | if (NewE->isArray()) |
302 | return; |
303 | |
304 | |
305 | const MemRegion *MR = C.getSVal(NewE).getAsRegion(); |
306 | if (!MR) |
307 | return; |
308 | |
309 | C.addTransition(setDynamicTypeInfo(C.getState(), MR, NewE->getType(), |
310 | )); |
311 | } |
312 | |
313 | const ObjCObjectType * |
314 | DynamicTypePropagation::getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE, |
315 | CheckerContext &C) const { |
316 | if (MsgE->getReceiverKind() == ObjCMessageExpr::Class) { |
317 | if (const ObjCObjectType *ObjTy |
318 | = MsgE->getClassReceiver()->getAs<ObjCObjectType>()) |
319 | return ObjTy; |
320 | } |
321 | |
322 | if (MsgE->getReceiverKind() == ObjCMessageExpr::SuperClass) { |
323 | if (const ObjCObjectType *ObjTy |
324 | = MsgE->getSuperType()->getAs<ObjCObjectType>()) |
325 | return ObjTy; |
326 | } |
327 | |
328 | const Expr *RecE = MsgE->getInstanceReceiver(); |
329 | if (!RecE) |
330 | return nullptr; |
331 | |
332 | RecE= RecE->IgnoreParenImpCasts(); |
333 | if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(RecE)) { |
334 | const StackFrameContext *SFCtx = C.getStackFrame(); |
335 | |
336 | |
337 | if (DRE->getDecl() == SFCtx->getSelfDecl()) { |
338 | if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(SFCtx->getDecl())) |
339 | if (const ObjCObjectType *ObjTy = |
340 | dyn_cast<ObjCObjectType>(MD->getClassInterface()->getTypeForDecl())) |
341 | return ObjTy; |
342 | } |
343 | } |
344 | return nullptr; |
345 | } |
346 | |
347 | |
348 | |
349 | |
350 | const ObjCObjectPointerType * |
351 | DynamicTypePropagation::getBetterObjCType(const Expr *CastE, |
352 | CheckerContext &C) const { |
353 | const MemRegion *ToR = C.getSVal(CastE).getAsRegion(); |
354 | assert(ToR); |
355 | |
356 | |
357 | const ObjCObjectPointerType *NewTy = |
358 | CastE->getType()->getAs<ObjCObjectPointerType>(); |
359 | if (!NewTy) |
360 | return nullptr; |
361 | QualType OldDTy = getDynamicTypeInfo(C.getState(), ToR).getType(); |
362 | if (OldDTy.isNull()) { |
363 | return NewTy; |
364 | } |
365 | const ObjCObjectPointerType *OldTy = |
366 | OldDTy->getAs<ObjCObjectPointerType>(); |
367 | if (!OldTy) |
368 | return nullptr; |
369 | |
370 | |
371 | if (OldTy->isObjCIdType() && !NewTy->isObjCIdType()) |
372 | return NewTy; |
373 | |
374 | |
375 | const ObjCInterfaceDecl *ToI = NewTy->getInterfaceDecl(); |
376 | const ObjCInterfaceDecl *FromI = OldTy->getInterfaceDecl(); |
377 | if (ToI && FromI && FromI->isSuperClassOf(ToI)) |
378 | return NewTy; |
379 | |
380 | return nullptr; |
381 | } |
382 | |
383 | static const ObjCObjectPointerType *getMostInformativeDerivedClassImpl( |
384 | const ObjCObjectPointerType *From, const ObjCObjectPointerType *To, |
385 | const ObjCObjectPointerType *MostInformativeCandidate, ASTContext &C) { |
386 | |
387 | if (From->getInterfaceDecl()->getCanonicalDecl() == |
388 | To->getInterfaceDecl()->getCanonicalDecl()) { |
389 | if (To->isSpecialized()) { |
390 | isSpecialized()", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp", 390, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(MostInformativeCandidate->isSpecialized()); |
391 | return MostInformativeCandidate; |
392 | } |
393 | return From; |
394 | } |
395 | |
396 | if (To->getObjectType()->getSuperClassType().isNull()) { |
397 | |
398 | |
399 | |
400 | return From; |
401 | } |
402 | |
403 | const auto *SuperOfTo = |
404 | To->getObjectType()->getSuperClassType()->getAs<ObjCObjectType>(); |
405 | assert(SuperOfTo); |
406 | QualType SuperPtrOfToQual = |
407 | C.getObjCObjectPointerType(QualType(SuperOfTo, 0)); |
408 | const auto *SuperPtrOfTo = SuperPtrOfToQual->getAs<ObjCObjectPointerType>(); |
409 | if (To->isUnspecialized()) |
410 | return getMostInformativeDerivedClassImpl(From, SuperPtrOfTo, SuperPtrOfTo, |
411 | C); |
412 | else |
413 | return getMostInformativeDerivedClassImpl(From, SuperPtrOfTo, |
414 | MostInformativeCandidate, C); |
415 | } |
416 | |
417 | |
418 | |
419 | |
420 | |
421 | |
422 | |
423 | |
424 | |
425 | |
426 | |
427 | |
428 | static const ObjCObjectPointerType * |
429 | getMostInformativeDerivedClass(const ObjCObjectPointerType *From, |
430 | const ObjCObjectPointerType *To, ASTContext &C) { |
431 | return getMostInformativeDerivedClassImpl(From, To, To, C); |
432 | } |
433 | |
434 | |
435 | |
436 | |
437 | |
438 | |
439 | |
440 | |
441 | |
442 | |
443 | |
444 | |
445 | |
446 | |
447 | |
448 | |
449 | |
450 | |
451 | |
452 | |
453 | |
454 | static bool |
455 | storeWhenMoreInformative(ProgramStateRef &State, SymbolRef Sym, |
456 | const ObjCObjectPointerType *const *Current, |
457 | const ObjCObjectPointerType *StaticLowerBound, |
458 | const ObjCObjectPointerType *StaticUpperBound, |
459 | ASTContext &C) { |
460 | |
461 | |
462 | |
463 | |
464 | |
465 | |
466 | |
467 | |
468 | |
469 | |
470 | |
471 | |
472 | |
473 | |
474 | |
475 | |
476 | |
477 | |
478 | isSpecialized() || StaticLowerBound->isSpecialized()", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp", 479, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(StaticUpperBound->isSpecialized() || |
479 | isSpecialized() || StaticLowerBound->isSpecialized()", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp", 479, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true"> StaticLowerBound->isSpecialized()); |
480 | isSpecialized()", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp", 480, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(!Current || (*Current)->isSpecialized()); |
481 | |
482 | |
483 | if (!Current) { |
484 | if (StaticUpperBound->isUnspecialized()) { |
485 | State = State->set<MostSpecializedTypeArgsMap>(Sym, StaticLowerBound); |
486 | return true; |
487 | } |
488 | |
489 | const ObjCObjectPointerType *WithMostInfo = |
490 | getMostInformativeDerivedClass(StaticUpperBound, StaticLowerBound, C); |
491 | State = State->set<MostSpecializedTypeArgsMap>(Sym, WithMostInfo); |
492 | return true; |
493 | } |
494 | |
495 | |
496 | if (C.canAssignObjCInterfaces(StaticLowerBound, *Current)) { |
497 | return false; |
498 | } |
499 | |
500 | |
501 | if (C.canAssignObjCInterfaces(*Current, StaticUpperBound)) { |
502 | |
503 | const ObjCObjectPointerType *WithMostInfo = |
504 | getMostInformativeDerivedClass(*Current, StaticUpperBound, C); |
505 | WithMostInfo = |
506 | getMostInformativeDerivedClass(WithMostInfo, StaticLowerBound, C); |
507 | if (WithMostInfo == *Current) |
508 | return false; |
509 | State = State->set<MostSpecializedTypeArgsMap>(Sym, WithMostInfo); |
510 | return true; |
511 | } |
512 | |
513 | |
514 | const ObjCObjectPointerType *WithMostInfo = |
515 | getMostInformativeDerivedClass(*Current, StaticLowerBound, C); |
516 | if (WithMostInfo != *Current) { |
517 | State = State->set<MostSpecializedTypeArgsMap>(Sym, WithMostInfo); |
518 | return true; |
519 | } |
520 | |
521 | return false; |
522 | } |
523 | |
524 | |
525 | |
526 | |
527 | void DynamicTypePropagation::checkPostStmt(const CastExpr *CE, |
528 | CheckerContext &C) const { |
529 | if (CE->getCastKind() != CK_BitCast) |
530 | return; |
531 | |
532 | QualType OriginType = CE->getSubExpr()->getType(); |
533 | QualType DestType = CE->getType(); |
534 | |
535 | const auto *OrigObjectPtrType = OriginType->getAs<ObjCObjectPointerType>(); |
536 | const auto *DestObjectPtrType = DestType->getAs<ObjCObjectPointerType>(); |
537 | |
538 | if (!OrigObjectPtrType || !DestObjectPtrType) |
539 | return; |
540 | |
541 | ProgramStateRef State = C.getState(); |
542 | ExplodedNode *AfterTypeProp = dynamicTypePropagationOnCasts(CE, State, C); |
543 | |
544 | ASTContext &ASTCtxt = C.getASTContext(); |
545 | |
546 | |
547 | |
548 | |
549 | |
550 | |
551 | OrigObjectPtrType = OrigObjectPtrType->stripObjCKindOfTypeAndQuals(ASTCtxt); |
552 | DestObjectPtrType = DestObjectPtrType->stripObjCKindOfTypeAndQuals(ASTCtxt); |
553 | |
554 | if (OrigObjectPtrType->isUnspecialized() && |
555 | DestObjectPtrType->isUnspecialized()) |
556 | return; |
557 | |
558 | SymbolRef Sym = C.getSVal(CE).getAsSymbol(); |
559 | if (!Sym) |
560 | return; |
561 | |
562 | const ObjCObjectPointerType *const *TrackedType = |
563 | State->get<MostSpecializedTypeArgsMap>(Sym); |
564 | |
565 | if (isa<ExplicitCastExpr>(CE)) { |
566 | |
567 | |
568 | |
569 | |
570 | |
571 | |
572 | |
573 | |
574 | if (TrackedType) { |
575 | State = State->remove<MostSpecializedTypeArgsMap>(Sym); |
576 | C.addTransition(State, AfterTypeProp); |
577 | } |
578 | return; |
579 | } |
580 | |
581 | |
582 | bool OrigToDest = |
583 | ASTCtxt.canAssignObjCInterfaces(DestObjectPtrType, OrigObjectPtrType); |
584 | bool DestToOrig = |
585 | ASTCtxt.canAssignObjCInterfaces(OrigObjectPtrType, DestObjectPtrType); |
586 | |
587 | |
588 | |
589 | |
590 | |
591 | if (TrackedType && |
592 | !ASTCtxt.canAssignObjCInterfaces(DestObjectPtrType, *TrackedType) && |
593 | !ASTCtxt.canAssignObjCInterfaces(*TrackedType, DestObjectPtrType)) { |
594 | static CheckerProgramPointTag IllegalConv(this, "IllegalConversion"); |
595 | ExplodedNode *N = C.addTransition(State, AfterTypeProp, &IllegalConv); |
596 | reportGenericsBug(*TrackedType, DestObjectPtrType, N, Sym, C); |
597 | return; |
598 | } |
599 | |
600 | |
601 | |
602 | const ObjCObjectPointerType *LowerBound = DestObjectPtrType; |
603 | const ObjCObjectPointerType *UpperBound = OrigObjectPtrType; |
604 | if (OrigToDest && !DestToOrig) |
605 | std::swap(LowerBound, UpperBound); |
606 | |
607 | |
608 | LowerBound = LowerBound->isObjCIdType() ? UpperBound : LowerBound; |
609 | UpperBound = UpperBound->isObjCIdType() ? LowerBound : UpperBound; |
610 | |
611 | if (storeWhenMoreInformative(State, Sym, TrackedType, LowerBound, UpperBound, |
612 | ASTCtxt)) { |
613 | C.addTransition(State, AfterTypeProp); |
614 | } |
615 | } |
616 | |
617 | static const Expr *stripCastsAndSugar(const Expr *E) { |
618 | E = E->IgnoreParenImpCasts(); |
619 | if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) |
620 | E = POE->getSyntacticForm()->IgnoreParenImpCasts(); |
621 | if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E)) |
622 | E = OVE->getSourceExpr()->IgnoreParenImpCasts(); |
623 | return E; |
624 | } |
625 | |
626 | static bool isObjCTypeParamDependent(QualType Type) { |
627 | |
628 | |
629 | |
630 | class IsObjCTypeParamDependentTypeVisitor |
631 | : public RecursiveASTVisitor<IsObjCTypeParamDependentTypeVisitor> { |
632 | public: |
633 | IsObjCTypeParamDependentTypeVisitor() : Result(false) {} |
634 | bool VisitObjCTypeParamType(const ObjCTypeParamType *Type) { |
635 | if (isa<ObjCTypeParamDecl>(Type->getDecl())) { |
636 | Result = true; |
637 | return false; |
638 | } |
639 | return true; |
640 | } |
641 | |
642 | bool Result; |
643 | }; |
644 | |
645 | IsObjCTypeParamDependentTypeVisitor Visitor; |
646 | Visitor.TraverseType(Type); |
647 | return Visitor.Result; |
648 | } |
649 | |
650 | |
651 | |
652 | |
653 | |
654 | |
655 | static const ObjCMethodDecl * |
656 | findMethodDecl(const ObjCMessageExpr *MessageExpr, |
657 | const ObjCObjectPointerType *TrackedType, ASTContext &ASTCtxt) { |
658 | const ObjCMethodDecl *Method = nullptr; |
659 | |
660 | QualType ReceiverType = MessageExpr->getReceiverType(); |
661 | const auto *ReceiverObjectPtrType = |
662 | ReceiverType->getAs<ObjCObjectPointerType>(); |
663 | |
664 | |
665 | |
666 | if (MessageExpr->getReceiverKind() == ObjCMessageExpr::Instance || |
667 | MessageExpr->getReceiverKind() == ObjCMessageExpr::Class) { |
668 | |
669 | |
670 | |
671 | if (ReceiverType->isObjCIdType() || ReceiverType->isObjCClassType() || |
672 | ASTCtxt.canAssignObjCInterfaces(ReceiverObjectPtrType, TrackedType)) { |
673 | const ObjCInterfaceDecl *InterfaceDecl = TrackedType->getInterfaceDecl(); |
674 | |
675 | Selector Sel = MessageExpr->getSelector(); |
676 | Method = InterfaceDecl->lookupInstanceMethod(Sel); |
677 | if (!Method) |
678 | Method = InterfaceDecl->lookupClassMethod(Sel); |
679 | } |
680 | } |
681 | |
682 | |
683 | |
684 | return Method ? Method : MessageExpr->getMethodDecl(); |
685 | } |
686 | |
687 | |
688 | |
689 | |
690 | static QualType getReturnTypeForMethod( |
691 | const ObjCMethodDecl *Method, ArrayRef<QualType> TypeArgs, |
692 | const ObjCObjectPointerType *SelfType, ASTContext &C) { |
693 | QualType StaticResultType = Method->getReturnType(); |
694 | |
695 | |
696 | if (StaticResultType == C.getObjCInstanceType()) |
697 | return QualType(SelfType, 0); |
698 | |
699 | |
700 | if (!isObjCTypeParamDependent(StaticResultType)) |
701 | return QualType(); |
702 | |
703 | QualType ResultType = StaticResultType.substObjCTypeArgs( |
704 | C, TypeArgs, ObjCSubstitutionContext::Result); |
705 | |
706 | return ResultType; |
707 | } |
708 | |
709 | |
710 | |
711 | void DynamicTypePropagation::checkPreObjCMessage(const ObjCMethodCall &M, |
712 | CheckerContext &C) const { |
713 | ProgramStateRef State = C.getState(); |
714 | SymbolRef Sym = M.getReceiverSVal().getAsSymbol(); |
715 | if (!Sym) |
716 | return; |
717 | |
718 | const ObjCObjectPointerType *const *TrackedType = |
719 | State->get<MostSpecializedTypeArgsMap>(Sym); |
720 | if (!TrackedType) |
721 | return; |
722 | |
723 | |
724 | |
725 | |
726 | ASTContext &ASTCtxt = C.getASTContext(); |
727 | const ObjCMessageExpr *MessageExpr = M.getOriginExpr(); |
728 | const ObjCMethodDecl *Method = |
729 | findMethodDecl(MessageExpr, *TrackedType, ASTCtxt); |
730 | |
731 | |
732 | if (!Method) |
733 | return; |
734 | |
735 | |
736 | |
737 | |
738 | |
739 | |
740 | |
741 | |
742 | |
743 | |
744 | |
745 | |
746 | |
747 | |
748 | |
749 | |
750 | |
751 | |
752 | |
753 | const ObjCInterfaceDecl *Interface = Method->getClassInterface(); |
754 | if (!Interface) |
755 | return; |
756 | |
757 | ObjCTypeParamList *TypeParams = Interface->getTypeParamList(); |
758 | if (!TypeParams) |
759 | return; |
760 | |
761 | for (ObjCTypeParamDecl *TypeParam : *TypeParams) { |
762 | if (TypeParam->getVariance() != ObjCTypeParamVariance::Invariant) |
763 | return; |
764 | } |
765 | |
766 | Optional<ArrayRef<QualType>> TypeArgs = |
767 | (*TrackedType)->getObjCSubstitutions(Method->getDeclContext()); |
768 | |
769 | |
770 | if (!TypeArgs) |
771 | return; |
772 | |
773 | for (unsigned i = 0; i < Method->param_size(); i++) { |
774 | const Expr *Arg = MessageExpr->getArg(i); |
775 | const ParmVarDecl *Param = Method->parameters()[i]; |
776 | |
777 | QualType OrigParamType = Param->getType(); |
778 | if (!isObjCTypeParamDependent(OrigParamType)) |
779 | continue; |
780 | |
781 | QualType ParamType = OrigParamType.substObjCTypeArgs( |
782 | ASTCtxt, *TypeArgs, ObjCSubstitutionContext::Parameter); |
783 | |
784 | const auto *ParamObjectPtrType = ParamType->getAs<ObjCObjectPointerType>(); |
785 | const auto *ArgObjectPtrType = |
786 | stripCastsAndSugar(Arg)->getType()->getAs<ObjCObjectPointerType>(); |
787 | if (!ParamObjectPtrType || !ArgObjectPtrType) |
788 | continue; |
789 | |
790 | |
791 | |
792 | SVal ArgSVal = M.getArgSVal(i); |
793 | SymbolRef ArgSym = ArgSVal.getAsSymbol(); |
794 | if (ArgSym) { |
795 | const ObjCObjectPointerType *const *TrackedArgType = |
796 | State->get<MostSpecializedTypeArgsMap>(ArgSym); |
797 | if (TrackedArgType && |
798 | ASTCtxt.canAssignObjCInterfaces(ArgObjectPtrType, *TrackedArgType)) { |
799 | ArgObjectPtrType = *TrackedArgType; |
800 | } |
801 | } |
802 | |
803 | |
804 | if (!ASTCtxt.canAssignObjCInterfaces(ParamObjectPtrType, |
805 | ArgObjectPtrType)) { |
806 | static CheckerProgramPointTag Tag(this, "ArgTypeMismatch"); |
807 | ExplodedNode *N = C.addTransition(State, &Tag); |
808 | reportGenericsBug(ArgObjectPtrType, ParamObjectPtrType, N, Sym, C, Arg); |
809 | return; |
810 | } |
811 | } |
812 | } |
813 | |
814 | |
815 | |
816 | |
817 | |
818 | |
819 | |
820 | |
821 | void DynamicTypePropagation::checkPostObjCMessage(const ObjCMethodCall &M, |
822 | CheckerContext &C) const { |
823 | const ObjCMessageExpr *MessageExpr = M.getOriginExpr(); |
824 | |
825 | SymbolRef RetSym = M.getReturnValue().getAsSymbol(); |
826 | if (!RetSym) |
827 | return; |
828 | |
829 | Selector Sel = MessageExpr->getSelector(); |
830 | ProgramStateRef State = C.getState(); |
831 | |
832 | |
833 | |
834 | if (MessageExpr->getReceiverKind() == ObjCMessageExpr::Class && |
835 | Sel.getAsString() == "class") { |
836 | QualType ReceiverType = MessageExpr->getClassReceiver(); |
837 | const auto *ReceiverClassType = ReceiverType->getAs<ObjCObjectType>(); |
838 | QualType ReceiverClassPointerType = |
839 | C.getASTContext().getObjCObjectPointerType( |
840 | QualType(ReceiverClassType, 0)); |
841 | |
842 | if (!ReceiverClassType->isSpecialized()) |
843 | return; |
844 | const auto *InferredType = |
845 | ReceiverClassPointerType->getAs<ObjCObjectPointerType>(); |
846 | assert(InferredType); |
847 | |
848 | State = State->set<MostSpecializedTypeArgsMap>(RetSym, InferredType); |
849 | C.addTransition(State); |
850 | return; |
851 | } |
852 | |
853 | |
854 | SymbolRef RecSym = M.getReceiverSVal().getAsSymbol(); |
855 | if (!RecSym) |
856 | return; |
857 | |
858 | const ObjCObjectPointerType *const *TrackedType = |
859 | State->get<MostSpecializedTypeArgsMap>(RecSym); |
860 | if (!TrackedType) |
861 | return; |
862 | |
863 | ASTContext &ASTCtxt = C.getASTContext(); |
864 | const ObjCMethodDecl *Method = |
865 | findMethodDecl(MessageExpr, *TrackedType, ASTCtxt); |
866 | if (!Method) |
867 | return; |
868 | |
869 | Optional<ArrayRef<QualType>> TypeArgs = |
870 | (*TrackedType)->getObjCSubstitutions(Method->getDeclContext()); |
871 | if (!TypeArgs) |
872 | return; |
873 | |
874 | QualType ResultType = |
875 | getReturnTypeForMethod(Method, *TypeArgs, *TrackedType, ASTCtxt); |
876 | |
877 | if (ResultType.isNull()) |
878 | return; |
879 | |
880 | const MemRegion *RetRegion = M.getReturnValue().getAsRegion(); |
881 | ExplodedNode *Pred = C.getPredecessor(); |
882 | |
883 | |
884 | |
885 | if (RetRegion && !State->get<DynamicTypeMap>(RetRegion)) { |
886 | |
887 | |
888 | |
889 | State = setDynamicTypeInfo(State, RetRegion, ResultType, |
890 | ); |
891 | Pred = C.addTransition(State); |
892 | } |
893 | |
894 | const auto *ResultPtrType = ResultType->getAs<ObjCObjectPointerType>(); |
895 | |
896 | if (!ResultPtrType || ResultPtrType->isUnspecialized()) |
897 | return; |
898 | |
899 | |
900 | |
901 | if (!State->get<MostSpecializedTypeArgsMap>(RetSym)) { |
902 | State = State->set<MostSpecializedTypeArgsMap>(RetSym, ResultPtrType); |
903 | C.addTransition(State, Pred); |
904 | } |
905 | } |
906 | |
907 | void DynamicTypePropagation::reportGenericsBug( |
908 | const ObjCObjectPointerType *From, const ObjCObjectPointerType *To, |
909 | ExplodedNode *N, SymbolRef Sym, CheckerContext &C, |
910 | const Stmt *ReportedNode) const { |
911 | if (!CheckGenerics) |
912 | return; |
913 | |
914 | initBugType(); |
915 | SmallString<192> Buf; |
916 | llvm::raw_svector_ostream OS(Buf); |
917 | OS << "Conversion from value of type '"; |
918 | QualType::print(From, Qualifiers(), OS, C.getLangOpts(), llvm::Twine()); |
919 | OS << "' to incompatible type '"; |
920 | QualType::print(To, Qualifiers(), OS, C.getLangOpts(), llvm::Twine()); |
921 | OS << "'"; |
922 | std::unique_ptr<BugReport> R( |
923 | new BugReport(*ObjCGenericsBugType, OS.str(), N)); |
924 | R->markInteresting(Sym); |
925 | R->addVisitor(llvm::make_unique<GenericsBugVisitor>(Sym)); |
926 | if (ReportedNode) |
927 | R->addRange(ReportedNode->getSourceRange()); |
928 | C.emitReport(std::move(R)); |
929 | } |
930 | |
931 | std::shared_ptr<PathDiagnosticPiece> |
932 | DynamicTypePropagation::GenericsBugVisitor::VisitNode(const ExplodedNode *N, |
933 | BugReporterContext &BRC, |
934 | BugReport &BR) { |
935 | ProgramStateRef state = N->getState(); |
936 | ProgramStateRef statePrev = N->getFirstPred()->getState(); |
937 | |
938 | const ObjCObjectPointerType *const *TrackedType = |
939 | state->get<MostSpecializedTypeArgsMap>(Sym); |
940 | const ObjCObjectPointerType *const *TrackedTypePrev = |
941 | statePrev->get<MostSpecializedTypeArgsMap>(Sym); |
942 | if (!TrackedType) |
943 | return nullptr; |
944 | |
945 | if (TrackedTypePrev && *TrackedTypePrev == *TrackedType) |
946 | return nullptr; |
947 | |
948 | |
949 | const Stmt *S = PathDiagnosticLocation::getStmt(N); |
950 | if (!S) |
951 | return nullptr; |
952 | |
953 | const LangOptions &LangOpts = BRC.getASTContext().getLangOpts(); |
954 | |
955 | SmallString<256> Buf; |
956 | llvm::raw_svector_ostream OS(Buf); |
957 | OS << "Type '"; |
958 | QualType::print(*TrackedType, Qualifiers(), OS, LangOpts, llvm::Twine()); |
959 | OS << "' is inferred from "; |
960 | |
961 | if (const auto *ExplicitCast = dyn_cast<ExplicitCastExpr>(S)) { |
962 | OS << "explicit cast (from '"; |
963 | QualType::print(ExplicitCast->getSubExpr()->getType().getTypePtr(), |
964 | Qualifiers(), OS, LangOpts, llvm::Twine()); |
965 | OS << "' to '"; |
966 | QualType::print(ExplicitCast->getType().getTypePtr(), Qualifiers(), OS, |
967 | LangOpts, llvm::Twine()); |
968 | OS << "')"; |
969 | } else if (const auto *ImplicitCast = dyn_cast<ImplicitCastExpr>(S)) { |
970 | OS << "implicit cast (from '"; |
971 | QualType::print(ImplicitCast->getSubExpr()->getType().getTypePtr(), |
972 | Qualifiers(), OS, LangOpts, llvm::Twine()); |
973 | OS << "' to '"; |
974 | QualType::print(ImplicitCast->getType().getTypePtr(), Qualifiers(), OS, |
975 | LangOpts, llvm::Twine()); |
976 | OS << "')"; |
977 | } else { |
978 | OS << "this context"; |
979 | } |
980 | |
981 | |
982 | PathDiagnosticLocation Pos(S, BRC.getSourceManager(), |
983 | N->getLocationContext()); |
984 | return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(), true, |
985 | nullptr); |
986 | } |
987 | |
988 | |
989 | void ento::registerObjCGenericsChecker(CheckerManager &mgr) { |
990 | DynamicTypePropagation *checker = mgr.getChecker<DynamicTypePropagation>(); |
991 | checker->CheckGenerics = true; |
992 | } |
993 | |
994 | bool ento::shouldRegisterObjCGenericsChecker(const LangOptions &LO) { |
995 | return true; |
996 | } |
997 | |
998 | void ento::registerDynamicTypePropagation(CheckerManager &mgr) { |
999 | mgr.registerChecker<DynamicTypePropagation>(); |
1000 | } |
1001 | |
1002 | bool ento::shouldRegisterDynamicTypePropagation(const LangOptions &LO) { |
1003 | return true; |
1004 | } |
1005 | |