1263509Sdim//== DynamicTypePropagation.cpp -------------------------------- -*- C++ -*--=//
2239313Sdim//
3239313Sdim//                     The LLVM Compiler Infrastructure
4239313Sdim//
5239313Sdim// This file is distributed under the University of Illinois Open Source
6239313Sdim// License. See LICENSE.TXT for details.
7239313Sdim//
8239313Sdim//===----------------------------------------------------------------------===//
9239313Sdim//
10239313Sdim// This checker defines the rules for dynamic type gathering and propagation.
11239313Sdim//
12239313Sdim//===----------------------------------------------------------------------===//
13239313Sdim
14239313Sdim#include "ClangSACheckers.h"
15252723Sdim#include "clang/Basic/Builtins.h"
16252723Sdim#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
17239313Sdim#include "clang/StaticAnalyzer/Core/Checker.h"
18239313Sdim#include "clang/StaticAnalyzer/Core/CheckerManager.h"
19239313Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
20239313Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
21239313Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
22239313Sdim
23239313Sdimusing namespace clang;
24239313Sdimusing namespace ento;
25239313Sdim
26239313Sdimnamespace {
27239313Sdimclass DynamicTypePropagation:
28239462Sdim    public Checker< check::PreCall,
29239462Sdim                    check::PostCall,
30252723Sdim                    check::PostStmt<ImplicitCastExpr>,
31252723Sdim                    check::PostStmt<CXXNewExpr> > {
32239313Sdim  const ObjCObjectType *getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE,
33239313Sdim                                                    CheckerContext &C) const;
34239313Sdim
35239313Sdim  /// \brief Return a better dynamic type if one can be derived from the cast.
36239313Sdim  const ObjCObjectPointerType *getBetterObjCType(const Expr *CastE,
37239313Sdim                                                 CheckerContext &C) const;
38239313Sdimpublic:
39239462Sdim  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
40239313Sdim  void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
41239313Sdim  void checkPostStmt(const ImplicitCastExpr *CastE, CheckerContext &C) const;
42252723Sdim  void checkPostStmt(const CXXNewExpr *NewE, CheckerContext &C) const;
43239313Sdim};
44239313Sdim}
45239313Sdim
46239462Sdimstatic void recordFixedType(const MemRegion *Region, const CXXMethodDecl *MD,
47239462Sdim                            CheckerContext &C) {
48239462Sdim  assert(Region);
49239462Sdim  assert(MD);
50239462Sdim
51239462Sdim  ASTContext &Ctx = C.getASTContext();
52239462Sdim  QualType Ty = Ctx.getPointerType(Ctx.getRecordType(MD->getParent()));
53239462Sdim
54239462Sdim  ProgramStateRef State = C.getState();
55239462Sdim  State = State->setDynamicTypeInfo(Region, Ty, /*CanBeSubclass=*/false);
56239462Sdim  C.addTransition(State);
57239462Sdim  return;
58239462Sdim}
59239462Sdim
60239462Sdimvoid DynamicTypePropagation::checkPreCall(const CallEvent &Call,
61239462Sdim                                          CheckerContext &C) const {
62239462Sdim  if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) {
63239462Sdim    // C++11 [class.cdtor]p4: When a virtual function is called directly or
64239462Sdim    //   indirectly from a constructor or from a destructor, including during
65263509Sdim    //   the construction or destruction of the class's non-static data members,
66239462Sdim    //   and the object to which the call applies is the object under
67239462Sdim    //   construction or destruction, the function called is the final overrider
68239462Sdim    //   in the constructor's or destructor's class and not one overriding it in
69239462Sdim    //   a more-derived class.
70239462Sdim
71239462Sdim    switch (Ctor->getOriginExpr()->getConstructionKind()) {
72239462Sdim    case CXXConstructExpr::CK_Complete:
73239462Sdim    case CXXConstructExpr::CK_Delegating:
74239462Sdim      // No additional type info necessary.
75239462Sdim      return;
76239462Sdim    case CXXConstructExpr::CK_NonVirtualBase:
77239462Sdim    case CXXConstructExpr::CK_VirtualBase:
78239462Sdim      if (const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion())
79239462Sdim        recordFixedType(Target, Ctor->getDecl(), C);
80239462Sdim      return;
81239462Sdim    }
82239462Sdim
83239462Sdim    return;
84239462Sdim  }
85239462Sdim
86239462Sdim  if (const CXXDestructorCall *Dtor = dyn_cast<CXXDestructorCall>(&Call)) {
87239462Sdim    // C++11 [class.cdtor]p4 (see above)
88245431Sdim    if (!Dtor->isBaseDestructor())
89245431Sdim      return;
90239462Sdim
91239462Sdim    const MemRegion *Target = Dtor->getCXXThisVal().getAsRegion();
92239462Sdim    if (!Target)
93239462Sdim      return;
94239462Sdim
95245431Sdim    const Decl *D = Dtor->getDecl();
96239462Sdim    if (!D)
97239462Sdim      return;
98239462Sdim
99239462Sdim    recordFixedType(Target, cast<CXXDestructorDecl>(D), C);
100239462Sdim    return;
101239462Sdim  }
102239462Sdim}
103239462Sdim
104239313Sdimvoid DynamicTypePropagation::checkPostCall(const CallEvent &Call,
105239313Sdim                                           CheckerContext &C) const {
106239313Sdim  // We can obtain perfect type info for return values from some calls.
107239313Sdim  if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(&Call)) {
108239313Sdim
109239313Sdim    // Get the returned value if it's a region.
110245431Sdim    const MemRegion *RetReg = Call.getReturnValue().getAsRegion();
111239313Sdim    if (!RetReg)
112239313Sdim      return;
113239313Sdim
114239313Sdim    ProgramStateRef State = C.getState();
115252723Sdim    const ObjCMethodDecl *D = Msg->getDecl();
116252723Sdim
117252723Sdim    if (D && D->hasRelatedResultType()) {
118252723Sdim      switch (Msg->getMethodFamily()) {
119252723Sdim      default:
120252723Sdim        break;
121239313Sdim
122252723Sdim      // We assume that the type of the object returned by alloc and new are the
123252723Sdim      // pointer to the object of the class specified in the receiver of the
124252723Sdim      // message.
125252723Sdim      case OMF_alloc:
126252723Sdim      case OMF_new: {
127252723Sdim        // Get the type of object that will get created.
128252723Sdim        const ObjCMessageExpr *MsgE = Msg->getOriginExpr();
129252723Sdim        const ObjCObjectType *ObjTy = getObjectTypeForAllocAndNew(MsgE, C);
130252723Sdim        if (!ObjTy)
131252723Sdim          return;
132252723Sdim        QualType DynResTy =
133239313Sdim                 C.getASTContext().getObjCObjectPointerType(QualType(ObjTy, 0));
134252723Sdim        C.addTransition(State->setDynamicTypeInfo(RetReg, DynResTy, false));
135252723Sdim        break;
136252723Sdim      }
137252723Sdim      case OMF_init: {
138252723Sdim        // Assume, the result of the init method has the same dynamic type as
139252723Sdim        // the receiver and propagate the dynamic type info.
140252723Sdim        const MemRegion *RecReg = Msg->getReceiverSVal().getAsRegion();
141252723Sdim        if (!RecReg)
142252723Sdim          return;
143252723Sdim        DynamicTypeInfo RecDynType = State->getDynamicTypeInfo(RecReg);
144252723Sdim        C.addTransition(State->setDynamicTypeInfo(RetReg, RecDynType));
145252723Sdim        break;
146252723Sdim      }
147252723Sdim      }
148239313Sdim    }
149239462Sdim    return;
150239313Sdim  }
151239462Sdim
152239462Sdim  if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) {
153239462Sdim    // We may need to undo the effects of our pre-call check.
154239462Sdim    switch (Ctor->getOriginExpr()->getConstructionKind()) {
155239462Sdim    case CXXConstructExpr::CK_Complete:
156239462Sdim    case CXXConstructExpr::CK_Delegating:
157239462Sdim      // No additional work necessary.
158239462Sdim      // Note: This will leave behind the actual type of the object for
159239462Sdim      // complete constructors, but arguably that's a good thing, since it
160239462Sdim      // means the dynamic type info will be correct even for objects
161239462Sdim      // constructed with operator new.
162239462Sdim      return;
163239462Sdim    case CXXConstructExpr::CK_NonVirtualBase:
164239462Sdim    case CXXConstructExpr::CK_VirtualBase:
165239462Sdim      if (const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion()) {
166239462Sdim        // We just finished a base constructor. Now we can use the subclass's
167239462Sdim        // type when resolving virtual calls.
168239462Sdim        const Decl *D = C.getLocationContext()->getDecl();
169239462Sdim        recordFixedType(Target, cast<CXXConstructorDecl>(D), C);
170239462Sdim      }
171239462Sdim      return;
172239462Sdim    }
173239462Sdim  }
174239313Sdim}
175239313Sdim
176239313Sdimvoid DynamicTypePropagation::checkPostStmt(const ImplicitCastExpr *CastE,
177239313Sdim                                           CheckerContext &C) const {
178239313Sdim  // We only track dynamic type info for regions.
179239313Sdim  const MemRegion *ToR = C.getSVal(CastE).getAsRegion();
180239313Sdim  if (!ToR)
181239313Sdim    return;
182239313Sdim
183239313Sdim  switch (CastE->getCastKind()) {
184239313Sdim  default:
185239313Sdim    break;
186239313Sdim  case CK_BitCast:
187239313Sdim    // Only handle ObjCObjects for now.
188239313Sdim    if (const Type *NewTy = getBetterObjCType(CastE, C))
189239313Sdim      C.addTransition(C.getState()->setDynamicTypeInfo(ToR, QualType(NewTy,0)));
190239313Sdim    break;
191239313Sdim  }
192239313Sdim  return;
193239313Sdim}
194239313Sdim
195252723Sdimvoid DynamicTypePropagation::checkPostStmt(const CXXNewExpr *NewE,
196252723Sdim                                           CheckerContext &C) const {
197252723Sdim  if (NewE->isArray())
198252723Sdim    return;
199252723Sdim
200252723Sdim  // We only track dynamic type info for regions.
201252723Sdim  const MemRegion *MR = C.getSVal(NewE).getAsRegion();
202252723Sdim  if (!MR)
203252723Sdim    return;
204252723Sdim
205252723Sdim  C.addTransition(C.getState()->setDynamicTypeInfo(MR, NewE->getType(),
206252723Sdim                                                   /*CanBeSubclass=*/false));
207252723Sdim}
208252723Sdim
209239313Sdimconst ObjCObjectType *
210239313SdimDynamicTypePropagation::getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE,
211239313Sdim                                                    CheckerContext &C) const {
212239313Sdim  if (MsgE->getReceiverKind() == ObjCMessageExpr::Class) {
213239313Sdim    if (const ObjCObjectType *ObjTy
214239313Sdim          = MsgE->getClassReceiver()->getAs<ObjCObjectType>())
215239313Sdim    return ObjTy;
216239313Sdim  }
217239313Sdim
218239313Sdim  if (MsgE->getReceiverKind() == ObjCMessageExpr::SuperClass) {
219239313Sdim    if (const ObjCObjectType *ObjTy
220239313Sdim          = MsgE->getSuperType()->getAs<ObjCObjectType>())
221239313Sdim      return ObjTy;
222239313Sdim  }
223239313Sdim
224239313Sdim  const Expr *RecE = MsgE->getInstanceReceiver();
225239313Sdim  if (!RecE)
226239313Sdim    return 0;
227239313Sdim
228239313Sdim  RecE= RecE->IgnoreParenImpCasts();
229239313Sdim  if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(RecE)) {
230239313Sdim    const StackFrameContext *SFCtx = C.getStackFrame();
231239313Sdim    // Are we calling [self alloc]? If this is self, get the type of the
232239313Sdim    // enclosing ObjC class.
233239313Sdim    if (DRE->getDecl() == SFCtx->getSelfDecl()) {
234239313Sdim      if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(SFCtx->getDecl()))
235239313Sdim        if (const ObjCObjectType *ObjTy =
236239313Sdim            dyn_cast<ObjCObjectType>(MD->getClassInterface()->getTypeForDecl()))
237239313Sdim          return ObjTy;
238239313Sdim    }
239239313Sdim  }
240239313Sdim  return 0;
241239313Sdim}
242239313Sdim
243239313Sdim// Return a better dynamic type if one can be derived from the cast.
244239313Sdim// Compare the current dynamic type of the region and the new type to which we
245239313Sdim// are casting. If the new type is lower in the inheritance hierarchy, pick it.
246239313Sdimconst ObjCObjectPointerType *
247239313SdimDynamicTypePropagation::getBetterObjCType(const Expr *CastE,
248239313Sdim                                          CheckerContext &C) const {
249239313Sdim  const MemRegion *ToR = C.getSVal(CastE).getAsRegion();
250239313Sdim  assert(ToR);
251239313Sdim
252239313Sdim  // Get the old and new types.
253239313Sdim  const ObjCObjectPointerType *NewTy =
254239313Sdim      CastE->getType()->getAs<ObjCObjectPointerType>();
255239313Sdim  if (!NewTy)
256239313Sdim    return 0;
257239313Sdim  QualType OldDTy = C.getState()->getDynamicTypeInfo(ToR).getType();
258239313Sdim  if (OldDTy.isNull()) {
259239313Sdim    return NewTy;
260239313Sdim  }
261239313Sdim  const ObjCObjectPointerType *OldTy =
262239313Sdim    OldDTy->getAs<ObjCObjectPointerType>();
263239313Sdim  if (!OldTy)
264239313Sdim    return 0;
265239313Sdim
266239313Sdim  // Id the old type is 'id', the new one is more precise.
267239313Sdim  if (OldTy->isObjCIdType() && !NewTy->isObjCIdType())
268239313Sdim    return NewTy;
269239313Sdim
270239313Sdim  // Return new if it's a subclass of old.
271239313Sdim  const ObjCInterfaceDecl *ToI = NewTy->getInterfaceDecl();
272239313Sdim  const ObjCInterfaceDecl *FromI = OldTy->getInterfaceDecl();
273239313Sdim  if (ToI && FromI && FromI->isSuperClassOf(ToI))
274239313Sdim    return NewTy;
275239313Sdim
276239313Sdim  return 0;
277239313Sdim}
278239313Sdim
279239313Sdimvoid ento::registerDynamicTypePropagation(CheckerManager &mgr) {
280239313Sdim  mgr.registerChecker<DynamicTypePropagation>();
281239313Sdim}
282