DynamicTypePropagation.cpp revision 55fc873017f10f6f566b182b70f6fc22aefa3464
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
23using namespace clang;
24using namespace ento;
25
26namespace {
27class DynamicTypePropagation:
28    public Checker< check::PreCall,
29                    check::PostCall,
30                    check::PostStmt<ImplicitCastExpr> > {
31  const ObjCObjectType *getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE,
32                                                    CheckerContext &C) const;
33
34  /// \brief Return a better dynamic type if one can be derived from the cast.
35  const ObjCObjectPointerType *getBetterObjCType(const Expr *CastE,
36                                                 CheckerContext &C) const;
37public:
38  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
39  void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
40  void checkPostStmt(const ImplicitCastExpr *CastE, CheckerContext &C) const;
41};
42}
43
44static void recordFixedType(const MemRegion *Region, const CXXMethodDecl *MD,
45                            CheckerContext &C) {
46  assert(Region);
47  assert(MD);
48
49  ASTContext &Ctx = C.getASTContext();
50  QualType Ty = Ctx.getPointerType(Ctx.getRecordType(MD->getParent()));
51
52  ProgramStateRef State = C.getState();
53  State = State->setDynamicTypeInfo(Region, Ty, /*CanBeSubclass=*/false);
54  C.addTransition(State);
55  return;
56}
57
58void DynamicTypePropagation::checkPreCall(const CallEvent &Call,
59                                          CheckerContext &C) const {
60  if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) {
61    // C++11 [class.cdtor]p4: When a virtual function is called directly or
62    //   indirectly from a constructor or from a destructor, including during
63    //   the construction or destruction of the class’s non-static data members,
64    //   and the object to which the call applies is the object under
65    //   construction or destruction, the function called is the final overrider
66    //   in the constructor's or destructor's class and not one overriding it in
67    //   a more-derived class.
68
69    switch (Ctor->getOriginExpr()->getConstructionKind()) {
70    case CXXConstructExpr::CK_Complete:
71    case CXXConstructExpr::CK_Delegating:
72      // No additional type info necessary.
73      return;
74    case CXXConstructExpr::CK_NonVirtualBase:
75    case CXXConstructExpr::CK_VirtualBase:
76      if (const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion())
77        recordFixedType(Target, Ctor->getDecl(), C);
78      return;
79    }
80
81    return;
82  }
83
84  if (const CXXDestructorCall *Dtor = dyn_cast<CXXDestructorCall>(&Call)) {
85    // C++11 [class.cdtor]p4 (see above)
86    if (!Dtor->isBaseDestructor())
87      return;
88
89    const MemRegion *Target = Dtor->getCXXThisVal().getAsRegion();
90    if (!Target)
91      return;
92
93    const Decl *D = Dtor->getDecl();
94    if (!D)
95      return;
96
97    recordFixedType(Target, cast<CXXDestructorDecl>(D), C);
98    return;
99  }
100}
101
102void DynamicTypePropagation::checkPostCall(const CallEvent &Call,
103                                           CheckerContext &C) const {
104  // We can obtain perfect type info for return values from some calls.
105  if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(&Call)) {
106
107    // Get the returned value if it's a region.
108    const MemRegion *RetReg = Call.getReturnValue().getAsRegion();
109    if (!RetReg)
110      return;
111
112    ProgramStateRef State = C.getState();
113
114    switch (Msg->getMethodFamily()) {
115    default:
116      break;
117
118    // We assume that the type of the object returned by alloc and new are the
119    // pointer to the object of the class specified in the receiver of the
120    // message.
121    case OMF_alloc:
122    case OMF_new: {
123      // Get the type of object that will get created.
124      const ObjCMessageExpr *MsgE = Msg->getOriginExpr();
125      const ObjCObjectType *ObjTy = getObjectTypeForAllocAndNew(MsgE, C);
126      if (!ObjTy)
127        return;
128      QualType DynResTy =
129                 C.getASTContext().getObjCObjectPointerType(QualType(ObjTy, 0));
130      C.addTransition(State->setDynamicTypeInfo(RetReg, DynResTy, false));
131      break;
132    }
133    case OMF_init: {
134      // Assume, the result of the init method has the same dynamic type as
135      // the receiver and propagate the dynamic type info.
136      const MemRegion *RecReg = Msg->getReceiverSVal().getAsRegion();
137      if (!RecReg)
138        return;
139      DynamicTypeInfo RecDynType = State->getDynamicTypeInfo(RecReg);
140      C.addTransition(State->setDynamicTypeInfo(RetReg, RecDynType));
141      break;
142    }
143    }
144
145    return;
146  }
147
148  if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) {
149    // We may need to undo the effects of our pre-call check.
150    switch (Ctor->getOriginExpr()->getConstructionKind()) {
151    case CXXConstructExpr::CK_Complete:
152    case CXXConstructExpr::CK_Delegating:
153      // No additional work necessary.
154      // Note: This will leave behind the actual type of the object for
155      // complete constructors, but arguably that's a good thing, since it
156      // means the dynamic type info will be correct even for objects
157      // constructed with operator new.
158      return;
159    case CXXConstructExpr::CK_NonVirtualBase:
160    case CXXConstructExpr::CK_VirtualBase:
161      if (const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion()) {
162        // We just finished a base constructor. Now we can use the subclass's
163        // type when resolving virtual calls.
164        const Decl *D = C.getLocationContext()->getDecl();
165        recordFixedType(Target, cast<CXXConstructorDecl>(D), C);
166      }
167      return;
168    }
169  }
170}
171
172void DynamicTypePropagation::checkPostStmt(const ImplicitCastExpr *CastE,
173                                           CheckerContext &C) const {
174  // We only track dynamic type info for regions.
175  const MemRegion *ToR = C.getSVal(CastE).getAsRegion();
176  if (!ToR)
177    return;
178
179  switch (CastE->getCastKind()) {
180  default:
181    break;
182  case CK_BitCast:
183    // Only handle ObjCObjects for now.
184    if (const Type *NewTy = getBetterObjCType(CastE, C))
185      C.addTransition(C.getState()->setDynamicTypeInfo(ToR, QualType(NewTy,0)));
186    break;
187  }
188  return;
189}
190
191const ObjCObjectType *
192DynamicTypePropagation::getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE,
193                                                    CheckerContext &C) const {
194  if (MsgE->getReceiverKind() == ObjCMessageExpr::Class) {
195    if (const ObjCObjectType *ObjTy
196          = MsgE->getClassReceiver()->getAs<ObjCObjectType>())
197    return ObjTy;
198  }
199
200  if (MsgE->getReceiverKind() == ObjCMessageExpr::SuperClass) {
201    if (const ObjCObjectType *ObjTy
202          = MsgE->getSuperType()->getAs<ObjCObjectType>())
203      return ObjTy;
204  }
205
206  const Expr *RecE = MsgE->getInstanceReceiver();
207  if (!RecE)
208    return 0;
209
210  RecE= RecE->IgnoreParenImpCasts();
211  if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(RecE)) {
212    const StackFrameContext *SFCtx = C.getStackFrame();
213    // Are we calling [self alloc]? If this is self, get the type of the
214    // enclosing ObjC class.
215    if (DRE->getDecl() == SFCtx->getSelfDecl()) {
216      if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(SFCtx->getDecl()))
217        if (const ObjCObjectType *ObjTy =
218            dyn_cast<ObjCObjectType>(MD->getClassInterface()->getTypeForDecl()))
219          return ObjTy;
220    }
221  }
222  return 0;
223}
224
225// Return a better dynamic type if one can be derived from the cast.
226// Compare the current dynamic type of the region and the new type to which we
227// are casting. If the new type is lower in the inheritance hierarchy, pick it.
228const ObjCObjectPointerType *
229DynamicTypePropagation::getBetterObjCType(const Expr *CastE,
230                                          CheckerContext &C) const {
231  const MemRegion *ToR = C.getSVal(CastE).getAsRegion();
232  assert(ToR);
233
234  // Get the old and new types.
235  const ObjCObjectPointerType *NewTy =
236      CastE->getType()->getAs<ObjCObjectPointerType>();
237  if (!NewTy)
238    return 0;
239  QualType OldDTy = C.getState()->getDynamicTypeInfo(ToR).getType();
240  if (OldDTy.isNull()) {
241    return NewTy;
242  }
243  const ObjCObjectPointerType *OldTy =
244    OldDTy->getAs<ObjCObjectPointerType>();
245  if (!OldTy)
246    return 0;
247
248  // Id the old type is 'id', the new one is more precise.
249  if (OldTy->isObjCIdType() && !NewTy->isObjCIdType())
250    return NewTy;
251
252  // Return new if it's a subclass of old.
253  const ObjCInterfaceDecl *ToI = NewTy->getInterfaceDecl();
254  const ObjCInterfaceDecl *FromI = OldTy->getInterfaceDecl();
255  if (ToI && FromI && FromI->isSuperClassOf(ToI))
256    return NewTy;
257
258  return 0;
259}
260
261void ento::registerDynamicTypePropagation(CheckerManager &mgr) {
262  mgr.registerChecker<DynamicTypePropagation>();
263}
264