1 //== DynamicTypePropagation.cpp -------------------------------- -*- C++ -*--=//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This checker defines the rules for dynamic type gathering and propagation.
12 //===----------------------------------------------------------------------===//
14 #include "ClangSACheckers.h"
15 #include "clang/Basic/Builtins.h"
16 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
17 #include "clang/StaticAnalyzer/Core/Checker.h"
18 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
19 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
20 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
21 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
23 using namespace clang;
27 class DynamicTypePropagation:
28 public Checker< check::PreCall,
30 check::PostStmt<ImplicitCastExpr>,
31 check::PostStmt<CXXNewExpr> > {
32 const ObjCObjectType *getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE,
33 CheckerContext &C) const;
35 /// \brief Return a better dynamic type if one can be derived from the cast.
36 const ObjCObjectPointerType *getBetterObjCType(const Expr *CastE,
37 CheckerContext &C) const;
39 void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
40 void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
41 void checkPostStmt(const ImplicitCastExpr *CastE, CheckerContext &C) const;
42 void checkPostStmt(const CXXNewExpr *NewE, CheckerContext &C) const;
46 static void recordFixedType(const MemRegion *Region, const CXXMethodDecl *MD,
51 ASTContext &Ctx = C.getASTContext();
52 QualType Ty = Ctx.getPointerType(Ctx.getRecordType(MD->getParent()));
54 ProgramStateRef State = C.getState();
55 State = State->setDynamicTypeInfo(Region, Ty, /*CanBeSubclass=*/false);
56 C.addTransition(State);
60 void DynamicTypePropagation::checkPreCall(const CallEvent &Call,
61 CheckerContext &C) const {
62 if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) {
63 // C++11 [class.cdtor]p4: When a virtual function is called directly or
64 // indirectly from a constructor or from a destructor, including during
65 // the construction or destruction of the class's non-static data members,
66 // and the object to which the call applies is the object under
67 // construction or destruction, the function called is the final overrider
68 // in the constructor's or destructor's class and not one overriding it in
69 // a more-derived class.
71 switch (Ctor->getOriginExpr()->getConstructionKind()) {
72 case CXXConstructExpr::CK_Complete:
73 case CXXConstructExpr::CK_Delegating:
74 // No additional type info necessary.
76 case CXXConstructExpr::CK_NonVirtualBase:
77 case CXXConstructExpr::CK_VirtualBase:
78 if (const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion())
79 recordFixedType(Target, Ctor->getDecl(), C);
86 if (const CXXDestructorCall *Dtor = dyn_cast<CXXDestructorCall>(&Call)) {
87 // C++11 [class.cdtor]p4 (see above)
88 if (!Dtor->isBaseDestructor())
91 const MemRegion *Target = Dtor->getCXXThisVal().getAsRegion();
95 const Decl *D = Dtor->getDecl();
99 recordFixedType(Target, cast<CXXDestructorDecl>(D), C);
104 void DynamicTypePropagation::checkPostCall(const CallEvent &Call,
105 CheckerContext &C) const {
106 // We can obtain perfect type info for return values from some calls.
107 if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(&Call)) {
109 // Get the returned value if it's a region.
110 const MemRegion *RetReg = Call.getReturnValue().getAsRegion();
114 ProgramStateRef State = C.getState();
115 const ObjCMethodDecl *D = Msg->getDecl();
117 if (D && D->hasRelatedResultType()) {
118 switch (Msg->getMethodFamily()) {
122 // We assume that the type of the object returned by alloc and new are the
123 // pointer to the object of the class specified in the receiver of the
127 // Get the type of object that will get created.
128 const ObjCMessageExpr *MsgE = Msg->getOriginExpr();
129 const ObjCObjectType *ObjTy = getObjectTypeForAllocAndNew(MsgE, C);
133 C.getASTContext().getObjCObjectPointerType(QualType(ObjTy, 0));
134 C.addTransition(State->setDynamicTypeInfo(RetReg, DynResTy, false));
138 // Assume, the result of the init method has the same dynamic type as
139 // the receiver and propagate the dynamic type info.
140 const MemRegion *RecReg = Msg->getReceiverSVal().getAsRegion();
143 DynamicTypeInfo RecDynType = State->getDynamicTypeInfo(RecReg);
144 C.addTransition(State->setDynamicTypeInfo(RetReg, RecDynType));
152 if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) {
153 // We may need to undo the effects of our pre-call check.
154 switch (Ctor->getOriginExpr()->getConstructionKind()) {
155 case CXXConstructExpr::CK_Complete:
156 case CXXConstructExpr::CK_Delegating:
157 // No additional work necessary.
158 // Note: This will leave behind the actual type of the object for
159 // complete constructors, but arguably that's a good thing, since it
160 // means the dynamic type info will be correct even for objects
161 // constructed with operator new.
163 case CXXConstructExpr::CK_NonVirtualBase:
164 case CXXConstructExpr::CK_VirtualBase:
165 if (const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion()) {
166 // We just finished a base constructor. Now we can use the subclass's
167 // type when resolving virtual calls.
168 const Decl *D = C.getLocationContext()->getDecl();
169 recordFixedType(Target, cast<CXXConstructorDecl>(D), C);
176 void DynamicTypePropagation::checkPostStmt(const ImplicitCastExpr *CastE,
177 CheckerContext &C) const {
178 // We only track dynamic type info for regions.
179 const MemRegion *ToR = C.getSVal(CastE).getAsRegion();
183 switch (CastE->getCastKind()) {
187 // Only handle ObjCObjects for now.
188 if (const Type *NewTy = getBetterObjCType(CastE, C))
189 C.addTransition(C.getState()->setDynamicTypeInfo(ToR, QualType(NewTy,0)));
195 void DynamicTypePropagation::checkPostStmt(const CXXNewExpr *NewE,
196 CheckerContext &C) const {
200 // We only track dynamic type info for regions.
201 const MemRegion *MR = C.getSVal(NewE).getAsRegion();
205 C.addTransition(C.getState()->setDynamicTypeInfo(MR, NewE->getType(),
206 /*CanBeSubclass=*/false));
209 const ObjCObjectType *
210 DynamicTypePropagation::getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE,
211 CheckerContext &C) const {
212 if (MsgE->getReceiverKind() == ObjCMessageExpr::Class) {
213 if (const ObjCObjectType *ObjTy
214 = MsgE->getClassReceiver()->getAs<ObjCObjectType>())
218 if (MsgE->getReceiverKind() == ObjCMessageExpr::SuperClass) {
219 if (const ObjCObjectType *ObjTy
220 = MsgE->getSuperType()->getAs<ObjCObjectType>())
224 const Expr *RecE = MsgE->getInstanceReceiver();
228 RecE= RecE->IgnoreParenImpCasts();
229 if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(RecE)) {
230 const StackFrameContext *SFCtx = C.getStackFrame();
231 // Are we calling [self alloc]? If this is self, get the type of the
232 // enclosing ObjC class.
233 if (DRE->getDecl() == SFCtx->getSelfDecl()) {
234 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(SFCtx->getDecl()))
235 if (const ObjCObjectType *ObjTy =
236 dyn_cast<ObjCObjectType>(MD->getClassInterface()->getTypeForDecl()))
243 // Return a better dynamic type if one can be derived from the cast.
244 // Compare the current dynamic type of the region and the new type to which we
245 // are casting. If the new type is lower in the inheritance hierarchy, pick it.
246 const ObjCObjectPointerType *
247 DynamicTypePropagation::getBetterObjCType(const Expr *CastE,
248 CheckerContext &C) const {
249 const MemRegion *ToR = C.getSVal(CastE).getAsRegion();
252 // Get the old and new types.
253 const ObjCObjectPointerType *NewTy =
254 CastE->getType()->getAs<ObjCObjectPointerType>();
257 QualType OldDTy = C.getState()->getDynamicTypeInfo(ToR).getType();
258 if (OldDTy.isNull()) {
261 const ObjCObjectPointerType *OldTy =
262 OldDTy->getAs<ObjCObjectPointerType>();
266 // Id the old type is 'id', the new one is more precise.
267 if (OldTy->isObjCIdType() && !NewTy->isObjCIdType())
270 // Return new if it's a subclass of old.
271 const ObjCInterfaceDecl *ToI = NewTy->getInterfaceDecl();
272 const ObjCInterfaceDecl *FromI = OldTy->getInterfaceDecl();
273 if (ToI && FromI && FromI->isSuperClassOf(ToI))
279 void ento::registerDynamicTypePropagation(CheckerManager &mgr) {
280 mgr.registerChecker<DynamicTypePropagation>();