• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- ObjCMessage.h - Wrapper for ObjC messages and dot syntax ---*- 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 file defines ObjCMessage which serves as a common wrapper for ObjC
11 // message expressions or implicit messages for loading/storing ObjC properties.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_OBJCMESSAGE
16 #define LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_OBJCMESSAGE
17 
18 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
19 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
20 #include "clang/AST/ExprObjC.h"
21 #include "clang/AST/ExprCXX.h"
22 #include "clang/Basic/SourceManager.h"
23 #include "llvm/ADT/PointerUnion.h"
24 #include "llvm/ADT/StringExtras.h"
25 #include "llvm/Support/Compiler.h"
26 
27 namespace clang {
28 namespace ento {
29 using llvm::StrInStrNoCase;
30 
31 /// \brief Represents both explicit ObjC message expressions and implicit
32 /// messages that are sent for handling properties in dot syntax.
33 class ObjCMessage {
34   const ObjCMessageExpr *Msg;
35   const ObjCPropertyRefExpr *PE;
36   const bool IsPropSetter;
37 public:
ObjCMessage()38   ObjCMessage() : Msg(0), PE(0), IsPropSetter(false) {}
39 
40   ObjCMessage(const ObjCMessageExpr *E, const ObjCPropertyRefExpr *pe = 0,
41               bool isSetter = false)
Msg(E)42     : Msg(E), PE(pe), IsPropSetter(isSetter) {
43     assert(E && "should not be initialized with null expression");
44   }
45 
isValid()46   bool isValid() const { return Msg; }
47 
isPureMessageExpr()48   bool isPureMessageExpr() const { return !PE; }
49 
isPropertyGetter()50   bool isPropertyGetter() const { return PE && !IsPropSetter; }
51 
isPropertySetter()52   bool isPropertySetter() const {
53     return IsPropSetter;
54   }
55 
getMessageExpr()56   const Expr *getMessageExpr() const {
57     return Msg;
58   }
59 
getType(ASTContext & ctx)60   QualType getType(ASTContext &ctx) const {
61     return Msg->getType();
62   }
63 
getResultType(ASTContext & ctx)64   QualType getResultType(ASTContext &ctx) const {
65     if (const ObjCMethodDecl *MD = Msg->getMethodDecl())
66       return MD->getResultType();
67     return getType(ctx);
68   }
69 
getMethodFamily()70   ObjCMethodFamily getMethodFamily() const {
71     return Msg->getMethodFamily();
72   }
73 
getSelector()74   Selector getSelector() const {
75     return Msg->getSelector();
76   }
77 
getInstanceReceiver()78   const Expr *getInstanceReceiver() const {
79     return Msg->getInstanceReceiver();
80   }
81 
getInstanceReceiverSVal(ProgramStateRef State,const LocationContext * LC)82   SVal getInstanceReceiverSVal(ProgramStateRef State,
83                                const LocationContext *LC) const {
84     if (!isInstanceMessage())
85       return UndefinedVal();
86     if (const Expr *Ex = getInstanceReceiver())
87       return State->getSValAsScalarOrLoc(Ex, LC);
88 
89     // An instance message with no expression means we are sending to super.
90     // In this case the object reference is the same as 'self'.
91     const ImplicitParamDecl *SelfDecl = LC->getSelfDecl();
92     assert(SelfDecl && "No message receiver Expr, but not in an ObjC method");
93     return State->getSVal(State->getRegion(SelfDecl, LC));
94   }
95 
isInstanceMessage()96   bool isInstanceMessage() const {
97     return Msg->isInstanceMessage();
98   }
99 
getMethodDecl()100   const ObjCMethodDecl *getMethodDecl() const {
101     return Msg->getMethodDecl();
102   }
103 
getReceiverInterface()104   const ObjCInterfaceDecl *getReceiverInterface() const {
105     return Msg->getReceiverInterface();
106   }
107 
getSuperLoc()108   SourceLocation getSuperLoc() const {
109     if (PE)
110       return PE->getReceiverLocation();
111     return Msg->getSuperLoc();
112   }
113 
getSourceRange()114   SourceRange getSourceRange() const LLVM_READONLY {
115     if (PE)
116       return PE->getSourceRange();
117     return Msg->getSourceRange();
118   }
119 
getNumArgs()120   unsigned getNumArgs() const {
121     return Msg->getNumArgs();
122   }
123 
getArgSVal(unsigned i,const LocationContext * LCtx,ProgramStateRef state)124   SVal getArgSVal(unsigned i,
125                   const LocationContext *LCtx,
126                   ProgramStateRef state) const {
127     assert(i < getNumArgs() && "Invalid index for argument");
128     return state->getSVal(Msg->getArg(i), LCtx);
129   }
130 
getArgType(unsigned i)131   QualType getArgType(unsigned i) const {
132     assert(i < getNumArgs() && "Invalid index for argument");
133     return Msg->getArg(i)->getType();
134   }
135 
getArgExpr(unsigned i)136   const Expr *getArgExpr(unsigned i) const {
137     assert(i < getNumArgs() && "Invalid index for argument");
138     return Msg->getArg(i);
139   }
140 
getArgSourceRange(unsigned i)141   SourceRange getArgSourceRange(unsigned i) const {
142     const Expr *argE = getArgExpr(i);
143     return argE->getSourceRange();
144   }
145 
getReceiverSourceRange()146   SourceRange getReceiverSourceRange() const {
147     if (PE) {
148       if (PE->isObjectReceiver())
149         return PE->getBase()->getSourceRange();
150     }
151     else {
152       return Msg->getReceiverRange();
153     }
154 
155     // FIXME: This isn't a range.
156     return PE->getReceiverLocation();
157   }
158 };
159 
160 /// \brief Common wrapper for a call expression, ObjC message, or C++
161 /// constructor, mainly to provide a common interface for their arguments.
162 class CallOrObjCMessage {
163   llvm::PointerUnion<const CallExpr *, const CXXConstructExpr *> CallE;
164   ObjCMessage Msg;
165   ProgramStateRef State;
166   const LocationContext *LCtx;
167 public:
CallOrObjCMessage(const CallExpr * callE,ProgramStateRef state,const LocationContext * lctx)168   CallOrObjCMessage(const CallExpr *callE, ProgramStateRef state,
169                     const LocationContext *lctx)
170     : CallE(callE), State(state), LCtx(lctx) {}
CallOrObjCMessage(const CXXConstructExpr * consE,ProgramStateRef state,const LocationContext * lctx)171   CallOrObjCMessage(const CXXConstructExpr *consE, ProgramStateRef state,
172                     const LocationContext *lctx)
173     : CallE(consE), State(state), LCtx(lctx) {}
CallOrObjCMessage(const ObjCMessage & msg,ProgramStateRef state,const LocationContext * lctx)174   CallOrObjCMessage(const ObjCMessage &msg, ProgramStateRef state,
175                     const LocationContext *lctx)
176     : CallE((CallExpr *)0), Msg(msg), State(state), LCtx(lctx) {}
177 
178   QualType getResultType(ASTContext &ctx) const;
179 
isFunctionCall()180   bool isFunctionCall() const {
181     return CallE && CallE.is<const CallExpr *>();
182   }
183 
isCXXConstructExpr()184   bool isCXXConstructExpr() const {
185     return CallE && CallE.is<const CXXConstructExpr *>();
186   }
187 
isObjCMessage()188   bool isObjCMessage() const {
189     return !CallE;
190   }
191 
isCXXCall()192   bool isCXXCall() const {
193     const CallExpr *ActualCallE = CallE.dyn_cast<const CallExpr *>();
194     return ActualCallE && isa<CXXMemberCallExpr>(ActualCallE);
195   }
196 
197   /// Check if the callee is declared in the system header.
isInSystemHeader()198   bool isInSystemHeader() const {
199     if (const Decl *FD = getDecl()) {
200       const SourceManager &SM =
201         State->getStateManager().getContext().getSourceManager();
202       return SM.isInSystemHeader(FD->getLocation());
203     }
204     return false;
205   }
206 
getOriginExpr()207   const Expr *getOriginExpr() const {
208     if (!CallE)
209       return Msg.getMessageExpr();
210     if (const CXXConstructExpr *Ctor =
211           CallE.dyn_cast<const CXXConstructExpr *>())
212       return Ctor;
213     return CallE.get<const CallExpr *>();
214   }
215 
216   SVal getFunctionCallee() const;
217   SVal getCXXCallee() const;
218   SVal getInstanceMessageReceiver(const LocationContext *LC) const;
219 
220   /// Get the declaration of the function or method.
221   const Decl *getDecl() const;
222 
getNumArgs()223   unsigned getNumArgs() const {
224     if (!CallE)
225       return Msg.getNumArgs();
226     if (const CXXConstructExpr *Ctor =
227           CallE.dyn_cast<const CXXConstructExpr *>())
228       return Ctor->getNumArgs();
229     return CallE.get<const CallExpr *>()->getNumArgs();
230   }
231 
getArgSVal(unsigned i)232   SVal getArgSVal(unsigned i) const {
233     assert(i < getNumArgs());
234     if (!CallE)
235       return Msg.getArgSVal(i, LCtx, State);
236     return State->getSVal(getArg(i), LCtx);
237   }
238 
getArg(unsigned i)239   const Expr *getArg(unsigned i) const {
240     assert(i < getNumArgs());
241     if (!CallE)
242       return Msg.getArgExpr(i);
243     if (const CXXConstructExpr *Ctor =
244           CallE.dyn_cast<const CXXConstructExpr *>())
245       return Ctor->getArg(i);
246     return CallE.get<const CallExpr *>()->getArg(i);
247   }
248 
getArgSourceRange(unsigned i)249   SourceRange getArgSourceRange(unsigned i) const {
250     assert(i < getNumArgs());
251     if (CallE)
252       return getArg(i)->getSourceRange();
253     return Msg.getArgSourceRange(i);
254   }
255 
getReceiverSourceRange()256   SourceRange getReceiverSourceRange() const {
257     assert(isObjCMessage());
258     return Msg.getReceiverSourceRange();
259   }
260 
261   /// \brief Check if the name corresponds to a CoreFoundation or CoreGraphics
262   /// function that allows objects to escape.
263   ///
264   /// Many methods allow a tracked object to escape.  For example:
265   ///
266   ///   CFMutableDictionaryRef x = CFDictionaryCreateMutable(..., customDeallocator);
267   ///   CFDictionaryAddValue(y, key, x);
268   ///
269   /// We handle this and similar cases with the following heuristic.  If the
270   /// function name contains "InsertValue", "SetValue", "AddValue",
271   /// "AppendValue", or "SetAttribute", then we assume that arguments may
272   /// escape.
273   //
274   // TODO: To reduce false negatives here, we should track the container
275   // allocation site and check if a proper deallocator was set there.
isCFCGAllowingEscape(StringRef FName)276   static bool isCFCGAllowingEscape(StringRef FName) {
277     if (FName[0] == 'C' && (FName[1] == 'F' || FName[1] == 'G'))
278            if (StrInStrNoCase(FName, "InsertValue") != StringRef::npos||
279                StrInStrNoCase(FName, "AddValue") != StringRef::npos ||
280                StrInStrNoCase(FName, "SetValue") != StringRef::npos ||
281                StrInStrNoCase(FName, "WithData") != StringRef::npos ||
282                StrInStrNoCase(FName, "AppendValue") != StringRef::npos||
283                StrInStrNoCase(FName, "SetAttribute") != StringRef::npos) {
284          return true;
285        }
286     return false;
287   }
288 };
289 
290 }
291 }
292 
293 #endif
294