DynamicTypePropagation.cpp revision 239462
1239313Sdim//== 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"
15239313Sdim#include "clang/StaticAnalyzer/Core/Checker.h"
16239313Sdim#include "clang/StaticAnalyzer/Core/CheckerManager.h"
17239313Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
18239313Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
19239313Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
20239313Sdim#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
21239313Sdim#include "clang/Basic/Builtins.h"
22239313Sdim
23239313Sdimusing namespace clang;
24239313Sdimusing namespace ento;
25239313Sdim
26239313Sdimnamespace {
27239313Sdimclass DynamicTypePropagation:
28239462Sdim    public Checker< check::PreCall,
29239462Sdim                    check::PostCall,
30239313Sdim                    check::PostStmt<ImplicitCastExpr> > {
31239313Sdim  const ObjCObjectType *getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE,
32239313Sdim                                                    CheckerContext &C) const;
33239313Sdim
34239313Sdim  /// \brief Return a better dynamic type if one can be derived from the cast.
35239313Sdim  const ObjCObjectPointerType *getBetterObjCType(const Expr *CastE,
36239313Sdim                                                 CheckerContext &C) const;
37239313Sdimpublic:
38239462Sdim  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
39239313Sdim  void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
40239313Sdim  void checkPostStmt(const ImplicitCastExpr *CastE, CheckerContext &C) const;
41239313Sdim};
42239313Sdim}
43239313Sdim
44239462Sdimstatic void recordFixedType(const MemRegion *Region, const CXXMethodDecl *MD,
45239462Sdim                            CheckerContext &C) {
46239462Sdim  assert(Region);
47239462Sdim  assert(MD);
48239462Sdim
49239462Sdim  ASTContext &Ctx = C.getASTContext();
50239462Sdim  QualType Ty = Ctx.getPointerType(Ctx.getRecordType(MD->getParent()));
51239462Sdim
52239462Sdim  ProgramStateRef State = C.getState();
53239462Sdim  State = State->setDynamicTypeInfo(Region, Ty, /*CanBeSubclass=*/false);
54239462Sdim  C.addTransition(State);
55239462Sdim  return;
56239462Sdim}
57239462Sdim
58239462Sdimvoid DynamicTypePropagation::checkPreCall(const CallEvent &Call,
59239462Sdim                                          CheckerContext &C) const {
60239462Sdim  if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) {
61239462Sdim    // C++11 [class.cdtor]p4: When a virtual function is called directly or
62239462Sdim    //   indirectly from a constructor or from a destructor, including during
63239462Sdim    //   the construction or destruction of the class���s non-static data members,
64239462Sdim    //   and the object to which the call applies is the object under
65239462Sdim    //   construction or destruction, the function called is the final overrider
66239462Sdim    //   in the constructor's or destructor's class and not one overriding it in
67239462Sdim    //   a more-derived class.
68239462Sdim
69239462Sdim    switch (Ctor->getOriginExpr()->getConstructionKind()) {
70239462Sdim    case CXXConstructExpr::CK_Complete:
71239462Sdim    case CXXConstructExpr::CK_Delegating:
72239462Sdim      // No additional type info necessary.
73239462Sdim      return;
74239462Sdim    case CXXConstructExpr::CK_NonVirtualBase:
75239462Sdim    case CXXConstructExpr::CK_VirtualBase:
76239462Sdim      if (const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion())
77239462Sdim        recordFixedType(Target, Ctor->getDecl(), C);
78239462Sdim      return;
79239462Sdim    }
80239462Sdim
81239462Sdim    return;
82239462Sdim  }
83239462Sdim
84239462Sdim  if (const CXXDestructorCall *Dtor = dyn_cast<CXXDestructorCall>(&Call)) {
85239462Sdim    // C++11 [class.cdtor]p4 (see above)
86239462Sdim
87239462Sdim    const MemRegion *Target = Dtor->getCXXThisVal().getAsRegion();
88239462Sdim    if (!Target)
89239462Sdim      return;
90239462Sdim
91239462Sdim    // FIXME: getRuntimeDefinition() can be expensive. It would be better to do
92239462Sdim    // this when we are entering the stack frame for the destructor.
93239462Sdim    const Decl *D = Dtor->getRuntimeDefinition().getDecl();
94239462Sdim    if (!D)
95239462Sdim      return;
96239462Sdim
97239462Sdim    recordFixedType(Target, cast<CXXDestructorDecl>(D), C);
98239462Sdim    return;
99239462Sdim  }
100239462Sdim}
101239462Sdim
102239313Sdimvoid DynamicTypePropagation::checkPostCall(const CallEvent &Call,
103239313Sdim                                           CheckerContext &C) const {
104239313Sdim  // We can obtain perfect type info for return values from some calls.
105239313Sdim  if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(&Call)) {
106239313Sdim
107239313Sdim    // Get the returned value if it's a region.
108239313Sdim    SVal Result = C.getSVal(Call.getOriginExpr());
109239313Sdim    const MemRegion *RetReg = Result.getAsRegion();
110239313Sdim    if (!RetReg)
111239313Sdim      return;
112239313Sdim
113239313Sdim    ProgramStateRef State = C.getState();
114239313Sdim
115239313Sdim    switch (Msg->getMethodFamily()) {
116239313Sdim    default:
117239313Sdim      break;
118239313Sdim
119239313Sdim    // We assume that the type of the object returned by alloc and new are the
120239313Sdim    // pointer to the object of the class specified in the receiver of the
121239313Sdim    // message.
122239313Sdim    case OMF_alloc:
123239313Sdim    case OMF_new: {
124239313Sdim      // Get the type of object that will get created.
125239313Sdim      const ObjCMessageExpr *MsgE = Msg->getOriginExpr();
126239313Sdim      const ObjCObjectType *ObjTy = getObjectTypeForAllocAndNew(MsgE, C);
127239313Sdim      if (!ObjTy)
128239313Sdim        return;
129239313Sdim      QualType DynResTy =
130239313Sdim                 C.getASTContext().getObjCObjectPointerType(QualType(ObjTy, 0));
131239313Sdim      C.addTransition(State->setDynamicTypeInfo(RetReg, DynResTy, false));
132239313Sdim      break;
133239313Sdim    }
134239313Sdim    case OMF_init: {
135239313Sdim      // Assume, the result of the init method has the same dynamic type as
136239313Sdim      // the receiver and propagate the dynamic type info.
137239313Sdim      const MemRegion *RecReg = Msg->getReceiverSVal().getAsRegion();
138239313Sdim      if (!RecReg)
139239313Sdim        return;
140239313Sdim      DynamicTypeInfo RecDynType = State->getDynamicTypeInfo(RecReg);
141239313Sdim      C.addTransition(State->setDynamicTypeInfo(RetReg, RecDynType));
142239313Sdim      break;
143239313Sdim    }
144239313Sdim    }
145239462Sdim
146239462Sdim    return;
147239313Sdim  }
148239462Sdim
149239462Sdim  if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) {
150239462Sdim    // We may need to undo the effects of our pre-call check.
151239462Sdim    switch (Ctor->getOriginExpr()->getConstructionKind()) {
152239462Sdim    case CXXConstructExpr::CK_Complete:
153239462Sdim    case CXXConstructExpr::CK_Delegating:
154239462Sdim      // No additional work necessary.
155239462Sdim      // Note: This will leave behind the actual type of the object for
156239462Sdim      // complete constructors, but arguably that's a good thing, since it
157239462Sdim      // means the dynamic type info will be correct even for objects
158239462Sdim      // constructed with operator new.
159239462Sdim      return;
160239462Sdim    case CXXConstructExpr::CK_NonVirtualBase:
161239462Sdim    case CXXConstructExpr::CK_VirtualBase:
162239462Sdim      if (const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion()) {
163239462Sdim        // We just finished a base constructor. Now we can use the subclass's
164239462Sdim        // type when resolving virtual calls.
165239462Sdim        const Decl *D = C.getLocationContext()->getDecl();
166239462Sdim        recordFixedType(Target, cast<CXXConstructorDecl>(D), C);
167239462Sdim      }
168239462Sdim      return;
169239462Sdim    }
170239462Sdim  }
171239313Sdim}
172239313Sdim
173239313Sdimvoid DynamicTypePropagation::checkPostStmt(const ImplicitCastExpr *CastE,
174239313Sdim                                           CheckerContext &C) const {
175239313Sdim  // We only track dynamic type info for regions.
176239313Sdim  const MemRegion *ToR = C.getSVal(CastE).getAsRegion();
177239313Sdim  if (!ToR)
178239313Sdim    return;
179239313Sdim
180239313Sdim  switch (CastE->getCastKind()) {
181239313Sdim  default:
182239313Sdim    break;
183239313Sdim  case CK_BitCast:
184239313Sdim    // Only handle ObjCObjects for now.
185239313Sdim    if (const Type *NewTy = getBetterObjCType(CastE, C))
186239313Sdim      C.addTransition(C.getState()->setDynamicTypeInfo(ToR, QualType(NewTy,0)));
187239313Sdim    break;
188239313Sdim  }
189239313Sdim  return;
190239313Sdim}
191239313Sdim
192239313Sdimconst ObjCObjectType *
193239313SdimDynamicTypePropagation::getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE,
194239313Sdim                                                    CheckerContext &C) const {
195239313Sdim  if (MsgE->getReceiverKind() == ObjCMessageExpr::Class) {
196239313Sdim    if (const ObjCObjectType *ObjTy
197239313Sdim          = MsgE->getClassReceiver()->getAs<ObjCObjectType>())
198239313Sdim    return ObjTy;
199239313Sdim  }
200239313Sdim
201239313Sdim  if (MsgE->getReceiverKind() == ObjCMessageExpr::SuperClass) {
202239313Sdim    if (const ObjCObjectType *ObjTy
203239313Sdim          = MsgE->getSuperType()->getAs<ObjCObjectType>())
204239313Sdim      return ObjTy;
205239313Sdim  }
206239313Sdim
207239313Sdim  const Expr *RecE = MsgE->getInstanceReceiver();
208239313Sdim  if (!RecE)
209239313Sdim    return 0;
210239313Sdim
211239313Sdim  RecE= RecE->IgnoreParenImpCasts();
212239313Sdim  if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(RecE)) {
213239313Sdim    const StackFrameContext *SFCtx = C.getStackFrame();
214239313Sdim    // Are we calling [self alloc]? If this is self, get the type of the
215239313Sdim    // enclosing ObjC class.
216239313Sdim    if (DRE->getDecl() == SFCtx->getSelfDecl()) {
217239313Sdim      if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(SFCtx->getDecl()))
218239313Sdim        if (const ObjCObjectType *ObjTy =
219239313Sdim            dyn_cast<ObjCObjectType>(MD->getClassInterface()->getTypeForDecl()))
220239313Sdim          return ObjTy;
221239313Sdim    }
222239313Sdim  }
223239313Sdim  return 0;
224239313Sdim}
225239313Sdim
226239313Sdim// Return a better dynamic type if one can be derived from the cast.
227239313Sdim// Compare the current dynamic type of the region and the new type to which we
228239313Sdim// are casting. If the new type is lower in the inheritance hierarchy, pick it.
229239313Sdimconst ObjCObjectPointerType *
230239313SdimDynamicTypePropagation::getBetterObjCType(const Expr *CastE,
231239313Sdim                                          CheckerContext &C) const {
232239313Sdim  const MemRegion *ToR = C.getSVal(CastE).getAsRegion();
233239313Sdim  assert(ToR);
234239313Sdim
235239313Sdim  // Get the old and new types.
236239313Sdim  const ObjCObjectPointerType *NewTy =
237239313Sdim      CastE->getType()->getAs<ObjCObjectPointerType>();
238239313Sdim  if (!NewTy)
239239313Sdim    return 0;
240239313Sdim  QualType OldDTy = C.getState()->getDynamicTypeInfo(ToR).getType();
241239313Sdim  if (OldDTy.isNull()) {
242239313Sdim    return NewTy;
243239313Sdim  }
244239313Sdim  const ObjCObjectPointerType *OldTy =
245239313Sdim    OldDTy->getAs<ObjCObjectPointerType>();
246239313Sdim  if (!OldTy)
247239313Sdim    return 0;
248239313Sdim
249239313Sdim  // Id the old type is 'id', the new one is more precise.
250239313Sdim  if (OldTy->isObjCIdType() && !NewTy->isObjCIdType())
251239313Sdim    return NewTy;
252239313Sdim
253239313Sdim  // Return new if it's a subclass of old.
254239313Sdim  const ObjCInterfaceDecl *ToI = NewTy->getInterfaceDecl();
255239313Sdim  const ObjCInterfaceDecl *FromI = OldTy->getInterfaceDecl();
256239313Sdim  if (ToI && FromI && FromI->isSuperClassOf(ToI))
257239313Sdim    return NewTy;
258239313Sdim
259239313Sdim  return 0;
260239313Sdim}
261239313Sdim
262239313Sdimvoid ento::registerDynamicTypePropagation(CheckerManager &mgr) {
263239313Sdim  mgr.registerChecker<DynamicTypePropagation>();
264239313Sdim}
265