DynamicTypePropagation.cpp revision db061e40d639da0d938f915f0eef9e9772019c22
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    const ObjCMethodDecl *D = Msg->getDecl();
114
115    if (D && D->hasRelatedResultType()) {
116      switch (Msg->getMethodFamily()) {
117      default:
118        break;
119
120      // We assume that the type of the object returned by alloc and new are the
121      // pointer to the object of the class specified in the receiver of the
122      // message.
123      case OMF_alloc:
124      case OMF_new: {
125        // Get the type of object that will get created.
126        const ObjCMessageExpr *MsgE = Msg->getOriginExpr();
127        const ObjCObjectType *ObjTy = getObjectTypeForAllocAndNew(MsgE, C);
128        if (!ObjTy)
129          return;
130        QualType DynResTy =
131                 C.getASTContext().getObjCObjectPointerType(QualType(ObjTy, 0));
132        C.addTransition(State->setDynamicTypeInfo(RetReg, DynResTy, false));
133        break;
134      }
135      case OMF_init: {
136        // Assume, the result of the init method has the same dynamic type as
137        // the receiver and propagate the dynamic type info.
138        const MemRegion *RecReg = Msg->getReceiverSVal().getAsRegion();
139        if (!RecReg)
140          return;
141        DynamicTypeInfo RecDynType = State->getDynamicTypeInfo(RecReg);
142        C.addTransition(State->setDynamicTypeInfo(RetReg, RecDynType));
143        break;
144      }
145      }
146    }
147    return;
148  }
149
150  if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) {
151    // We may need to undo the effects of our pre-call check.
152    switch (Ctor->getOriginExpr()->getConstructionKind()) {
153    case CXXConstructExpr::CK_Complete:
154    case CXXConstructExpr::CK_Delegating:
155      // No additional work necessary.
156      // Note: This will leave behind the actual type of the object for
157      // complete constructors, but arguably that's a good thing, since it
158      // means the dynamic type info will be correct even for objects
159      // constructed with operator new.
160      return;
161    case CXXConstructExpr::CK_NonVirtualBase:
162    case CXXConstructExpr::CK_VirtualBase:
163      if (const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion()) {
164        // We just finished a base constructor. Now we can use the subclass's
165        // type when resolving virtual calls.
166        const Decl *D = C.getLocationContext()->getDecl();
167        recordFixedType(Target, cast<CXXConstructorDecl>(D), C);
168      }
169      return;
170    }
171  }
172}
173
174void DynamicTypePropagation::checkPostStmt(const ImplicitCastExpr *CastE,
175                                           CheckerContext &C) const {
176  // We only track dynamic type info for regions.
177  const MemRegion *ToR = C.getSVal(CastE).getAsRegion();
178  if (!ToR)
179    return;
180
181  switch (CastE->getCastKind()) {
182  default:
183    break;
184  case CK_BitCast:
185    // Only handle ObjCObjects for now.
186    if (const Type *NewTy = getBetterObjCType(CastE, C))
187      C.addTransition(C.getState()->setDynamicTypeInfo(ToR, QualType(NewTy,0)));
188    break;
189  }
190  return;
191}
192
193const ObjCObjectType *
194DynamicTypePropagation::getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE,
195                                                    CheckerContext &C) const {
196  if (MsgE->getReceiverKind() == ObjCMessageExpr::Class) {
197    if (const ObjCObjectType *ObjTy
198          = MsgE->getClassReceiver()->getAs<ObjCObjectType>())
199    return ObjTy;
200  }
201
202  if (MsgE->getReceiverKind() == ObjCMessageExpr::SuperClass) {
203    if (const ObjCObjectType *ObjTy
204          = MsgE->getSuperType()->getAs<ObjCObjectType>())
205      return ObjTy;
206  }
207
208  const Expr *RecE = MsgE->getInstanceReceiver();
209  if (!RecE)
210    return 0;
211
212  RecE= RecE->IgnoreParenImpCasts();
213  if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(RecE)) {
214    const StackFrameContext *SFCtx = C.getStackFrame();
215    // Are we calling [self alloc]? If this is self, get the type of the
216    // enclosing ObjC class.
217    if (DRE->getDecl() == SFCtx->getSelfDecl()) {
218      if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(SFCtx->getDecl()))
219        if (const ObjCObjectType *ObjTy =
220            dyn_cast<ObjCObjectType>(MD->getClassInterface()->getTypeForDecl()))
221          return ObjTy;
222    }
223  }
224  return 0;
225}
226
227// Return a better dynamic type if one can be derived from the cast.
228// Compare the current dynamic type of the region and the new type to which we
229// are casting. If the new type is lower in the inheritance hierarchy, pick it.
230const ObjCObjectPointerType *
231DynamicTypePropagation::getBetterObjCType(const Expr *CastE,
232                                          CheckerContext &C) const {
233  const MemRegion *ToR = C.getSVal(CastE).getAsRegion();
234  assert(ToR);
235
236  // Get the old and new types.
237  const ObjCObjectPointerType *NewTy =
238      CastE->getType()->getAs<ObjCObjectPointerType>();
239  if (!NewTy)
240    return 0;
241  QualType OldDTy = C.getState()->getDynamicTypeInfo(ToR).getType();
242  if (OldDTy.isNull()) {
243    return NewTy;
244  }
245  const ObjCObjectPointerType *OldTy =
246    OldDTy->getAs<ObjCObjectPointerType>();
247  if (!OldTy)
248    return 0;
249
250  // Id the old type is 'id', the new one is more precise.
251  if (OldTy->isObjCIdType() && !NewTy->isObjCIdType())
252    return NewTy;
253
254  // Return new if it's a subclass of old.
255  const ObjCInterfaceDecl *ToI = NewTy->getInterfaceDecl();
256  const ObjCInterfaceDecl *FromI = OldTy->getInterfaceDecl();
257  if (ToI && FromI && FromI->isSuperClassOf(ToI))
258    return NewTy;
259
260  return 0;
261}
262
263void ento::registerDynamicTypePropagation(CheckerManager &mgr) {
264  mgr.registerChecker<DynamicTypePropagation>();
265}
266