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