clang  3.7.0
DynamicTypePropagation.cpp
Go to the documentation of this file.
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"
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 
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 
55  State = State->setDynamicTypeInfo(Region, Ty, /*CanBeSubclass=*/false);
56  C.addTransition(State);
57  return;
58 }
59 
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.
70 
71  switch (Ctor->getOriginExpr()->getConstructionKind()) {
74  // No additional type info necessary.
75  return;
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 
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)) {
108 
109  // Get the returned value if it's a region.
110  const MemRegion *RetReg = Call.getReturnValue().getAsRegion();
111  if (!RetReg)
112  return;
113 
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 =
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()) {
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;
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 
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();
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 
195 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 *
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>())
215  return ObjTy;
216  }
217 
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 *
247 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 
279 void ento::registerDynamicTypePropagation(CheckerManager &mgr) {
280  mgr.registerChecker<DynamicTypePropagation>();
281 }
CastKind getCastKind() const
Definition: Expr.h:2709
MemRegion - The root abstract class for all memory regions.
Definition: MemRegion.h:77
QualType getClassReceiver() const
Returns the type of a class message send, or NULL if the message is not a class message.
Definition: ExprObjC.h:1171
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph). Uses the default CheckerContex...
QualType getRecordType(const RecordDecl *Decl) const
static void recordFixedType(const MemRegion *Region, const CXXMethodDecl *MD, CheckerContext &C)
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:89
LineState State
Represents any expression that calls an Objective-C method.
Definition: CallEvent.h:791
QualType getSuperType() const
Retrieve the type referred to by 'super'.
Definition: ExprObjC.h:1228
const CXXRecordDecl * getParent() const
Definition: DeclCXX.h:1817
Represents an ObjC class declaration.
Definition: DeclObjC.h:851
const ProgramStateRef & getState() const
Stores the currently inferred strictest bound on the runtime type of a region in a given state along ...
Represents an implicit call to a C++ destructor.
Definition: CallEvent.h:639
bool hasRelatedResultType() const
Determine whether this method has a result type that is related to the message receiver's type...
Definition: DeclObjC.h:276
An expression that sends a message to the given Objective-C object or class.
Definition: ExprObjC.h:858
bool isArray() const
Definition: ExprCXX.h:1713
CHECKER * registerChecker()
Used to register checkers.
Represents a new-expression for memory allocation and constructor calls, e.g: "new CXXNewExpr(foo)"...
Definition: ExprCXX.h:1623
Represents a static or instance method of a struct/union/class.
Definition: DeclCXX.h:1717
const Decl * getDecl() const
const StackFrameContext * getStackFrame() const
Expr * getInstanceReceiver()
Returns the object expression (receiver) for an instance message, or null for a message that is not a...
Definition: ExprObjC.h:1152
bool isSuperClassOf(const ObjCInterfaceDecl *I) const
Definition: DeclObjC.h:1476
QualType getType() const
Definition: Expr.h:125
QualType getPointerType(QualType T) const
Return the uniqued reference to the type for a pointer to the specified type.
QualType getObjCObjectPointerType(QualType OIT) const
Return a ObjCObjectPointerType type for the given ObjCObjectType.
const MemRegion * getAsRegion() const
Definition: SVals.cpp:135
Represents an abstract call to a function or method along a particular path.
Definition: CallEvent.h:113
Expr * IgnoreParenImpCasts() LLVM_READONLY
Definition: Expr.cpp:2526
const T * getAs() const
Definition: Type.h:5555
ObjCInterfaceDecl * getInterfaceDecl() const
Definition: Type.h:4835
const ImplicitParamDecl * getSelfDecl() const
The receiver is a class.
Definition: ExprObjC.h:1000
A reference to a declared variable, function, enum, etc. [C99 6.5.1p2].
Definition: Expr.h:899
bool isNull() const
isNull - Return true if this QualType doesn't point to a type yet.
Definition: Type.h:633
The receiver is a superclass.
Definition: ExprObjC.h:1004
SVal getReturnValue() const
Returns the return value of the call.
Definition: CallEvent.cpp:209
bool isObjCIdType() const
Definition: Type.h:4841
Represents a call to a C++ constructor.
Definition: CallEvent.h:687
ReceiverKind getReceiverKind() const
Determine the kind of receiver that this message is being sent to.
Definition: ExprObjC.h:1133
Defines enum values for all the target-independent builtin functions.
const LocationContext * getLocationContext() const
SVal getSVal(const Stmt *S) const
Get the value of arbitrary expressions at this point in the path.