1 //== DynamicTypePropagation.cpp -------------------------------- -*- C++ -*--=//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This checker defines the rules for dynamic type gathering and propagation.
11 //
12 //===----------------------------------------------------------------------===//
13
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"
22
23 using namespace clang;
24 using namespace ento;
25
26 namespace {
27 class DynamicTypePropagation:
28 public Checker< check::PreCall,
29 check::PostCall,
30 check::PostStmt<ImplicitCastExpr>,
31 check::PostStmt<CXXNewExpr> > {
32 const ObjCObjectType *getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE,
33 CheckerContext &C) const;
34
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;
38 public:
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;
43 };
44 }
45
recordFixedType(const MemRegion * Region,const CXXMethodDecl * MD,CheckerContext & C)46 static void recordFixedType(const MemRegion *Region, const CXXMethodDecl *MD,
47 CheckerContext &C) {
48 assert(Region);
49 assert(MD);
50
51 ASTContext &Ctx = C.getASTContext();
52 QualType Ty = Ctx.getPointerType(Ctx.getRecordType(MD->getParent()));
53
54 ProgramStateRef State = C.getState();
55 State = State->setDynamicTypeInfo(Region, Ty, /*CanBeSubclass=*/false);
56 C.addTransition(State);
57 return;
58 }
59
checkPreCall(const CallEvent & Call,CheckerContext & C) const60 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.
70
71 switch (Ctor->getOriginExpr()->getConstructionKind()) {
72 case CXXConstructExpr::CK_Complete:
73 case CXXConstructExpr::CK_Delegating:
74 // No additional type info necessary.
75 return;
76 case CXXConstructExpr::CK_NonVirtualBase:
77 case CXXConstructExpr::CK_VirtualBase:
78 if (const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion())
79 recordFixedType(Target, Ctor->getDecl(), C);
80 return;
81 }
82
83 return;
84 }
85
86 if (const CXXDestructorCall *Dtor = dyn_cast<CXXDestructorCall>(&Call)) {
87 // C++11 [class.cdtor]p4 (see above)
88 if (!Dtor->isBaseDestructor())
89 return;
90
91 const MemRegion *Target = Dtor->getCXXThisVal().getAsRegion();
92 if (!Target)
93 return;
94
95 const Decl *D = Dtor->getDecl();
96 if (!D)
97 return;
98
99 recordFixedType(Target, cast<CXXDestructorDecl>(D), C);
100 return;
101 }
102 }
103
checkPostCall(const CallEvent & Call,CheckerContext & C) const104 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)) {
108
109 // Get the returned value if it's a region.
110 const MemRegion *RetReg = Call.getReturnValue().getAsRegion();
111 if (!RetReg)
112 return;
113
114 ProgramStateRef State = C.getState();
115 const ObjCMethodDecl *D = Msg->getDecl();
116
117 if (D && D->hasRelatedResultType()) {
118 switch (Msg->getMethodFamily()) {
119 default:
120 break;
121
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
124 // message.
125 case OMF_alloc:
126 case OMF_new: {
127 // Get the type of object that will get created.
128 const ObjCMessageExpr *MsgE = Msg->getOriginExpr();
129 const ObjCObjectType *ObjTy = getObjectTypeForAllocAndNew(MsgE, C);
130 if (!ObjTy)
131 return;
132 QualType DynResTy =
133 C.getASTContext().getObjCObjectPointerType(QualType(ObjTy, 0));
134 C.addTransition(State->setDynamicTypeInfo(RetReg, DynResTy, false));
135 break;
136 }
137 case OMF_init: {
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();
141 if (!RecReg)
142 return;
143 DynamicTypeInfo RecDynType = State->getDynamicTypeInfo(RecReg);
144 C.addTransition(State->setDynamicTypeInfo(RetReg, RecDynType));
145 break;
146 }
147 }
148 }
149 return;
150 }
151
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.
162 return;
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);
170 }
171 return;
172 }
173 }
174 }
175
checkPostStmt(const ImplicitCastExpr * CastE,CheckerContext & C) const176 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();
180 if (!ToR)
181 return;
182
183 switch (CastE->getCastKind()) {
184 default:
185 break;
186 case CK_BitCast:
187 // Only handle ObjCObjects for now.
188 if (const Type *NewTy = getBetterObjCType(CastE, C))
189 C.addTransition(C.getState()->setDynamicTypeInfo(ToR, QualType(NewTy,0)));
190 break;
191 }
192 return;
193 }
194
checkPostStmt(const CXXNewExpr * NewE,CheckerContext & C) const195 void DynamicTypePropagation::checkPostStmt(const CXXNewExpr *NewE,
196 CheckerContext &C) const {
197 if (NewE->isArray())
198 return;
199
200 // We only track dynamic type info for regions.
201 const MemRegion *MR = C.getSVal(NewE).getAsRegion();
202 if (!MR)
203 return;
204
205 C.addTransition(C.getState()->setDynamicTypeInfo(MR, NewE->getType(),
206 /*CanBeSubclass=*/false));
207 }
208
209 const ObjCObjectType *
getObjectTypeForAllocAndNew(const ObjCMessageExpr * MsgE,CheckerContext & C) const210 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>())
215 return ObjTy;
216 }
217
218 if (MsgE->getReceiverKind() == ObjCMessageExpr::SuperClass) {
219 if (const ObjCObjectType *ObjTy
220 = MsgE->getSuperType()->getAs<ObjCObjectType>())
221 return ObjTy;
222 }
223
224 const Expr *RecE = MsgE->getInstanceReceiver();
225 if (!RecE)
226 return nullptr;
227
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()))
237 return ObjTy;
238 }
239 }
240 return nullptr;
241 }
242
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 *
getBetterObjCType(const Expr * CastE,CheckerContext & C) const247 DynamicTypePropagation::getBetterObjCType(const Expr *CastE,
248 CheckerContext &C) const {
249 const MemRegion *ToR = C.getSVal(CastE).getAsRegion();
250 assert(ToR);
251
252 // Get the old and new types.
253 const ObjCObjectPointerType *NewTy =
254 CastE->getType()->getAs<ObjCObjectPointerType>();
255 if (!NewTy)
256 return nullptr;
257 QualType OldDTy = C.getState()->getDynamicTypeInfo(ToR).getType();
258 if (OldDTy.isNull()) {
259 return NewTy;
260 }
261 const ObjCObjectPointerType *OldTy =
262 OldDTy->getAs<ObjCObjectPointerType>();
263 if (!OldTy)
264 return nullptr;
265
266 // Id the old type is 'id', the new one is more precise.
267 if (OldTy->isObjCIdType() && !NewTy->isObjCIdType())
268 return NewTy;
269
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))
274 return NewTy;
275
276 return nullptr;
277 }
278
registerDynamicTypePropagation(CheckerManager & mgr)279 void ento::registerDynamicTypePropagation(CheckerManager &mgr) {
280 mgr.registerChecker<DynamicTypePropagation>();
281 }
282