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: 38 ObjCMessage() : Msg(0), PE(0), IsPropSetter(false) {} 39 40 ObjCMessage(const ObjCMessageExpr *E, const ObjCPropertyRefExpr *pe = 0, 41 bool isSetter = false) 42 : Msg(E), PE(pe), IsPropSetter(isSetter) { 43 assert(E && "should not be initialized with null expression"); 44 } 45 46 bool isValid() const { return Msg; } 47 48 bool isPureMessageExpr() const { return !PE; } 49 50 bool isPropertyGetter() const { return PE && !IsPropSetter; } 51 52 bool isPropertySetter() const { 53 return IsPropSetter; 54 } 55 56 const Expr *getMessageExpr() const { 57 return Msg; 58 } 59 60 QualType getType(ASTContext &ctx) const { 61 return Msg->getType(); 62 } 63 64 QualType getResultType(ASTContext &ctx) const { 65 if (const ObjCMethodDecl *MD = Msg->getMethodDecl()) 66 return MD->getResultType(); 67 return getType(ctx); 68 } 69 70 ObjCMethodFamily getMethodFamily() const { 71 return Msg->getMethodFamily(); 72 } 73 74 Selector getSelector() const { 75 return Msg->getSelector(); 76 } 77 78 const Expr *getInstanceReceiver() const { 79 return Msg->getInstanceReceiver(); 80 } 81 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 96 bool isInstanceMessage() const { 97 return Msg->isInstanceMessage(); 98 } 99 100 const ObjCMethodDecl *getMethodDecl() const { 101 return Msg->getMethodDecl(); 102 } 103 104 const ObjCInterfaceDecl *getReceiverInterface() const { 105 return Msg->getReceiverInterface(); 106 } 107 108 SourceLocation getSuperLoc() const { 109 if (PE) 110 return PE->getReceiverLocation(); 111 return Msg->getSuperLoc(); 112 } 113 114 SourceRange getSourceRange() const LLVM_READONLY { 115 if (PE) 116 return PE->getSourceRange(); 117 return Msg->getSourceRange(); 118 } 119 120 unsigned getNumArgs() const { 121 return Msg->getNumArgs(); 122 } 123 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 131 QualType getArgType(unsigned i) const { 132 assert(i < getNumArgs() && "Invalid index for argument"); 133 return Msg->getArg(i)->getType(); 134 } 135 136 const Expr *getArgExpr(unsigned i) const { 137 assert(i < getNumArgs() && "Invalid index for argument"); 138 return Msg->getArg(i); 139 } 140 141 SourceRange getArgSourceRange(unsigned i) const { 142 const Expr *argE = getArgExpr(i); 143 return argE->getSourceRange(); 144 } 145 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: 168 CallOrObjCMessage(const CallExpr *callE, ProgramStateRef state, 169 const LocationContext *lctx) 170 : CallE(callE), State(state), LCtx(lctx) {} 171 CallOrObjCMessage(const CXXConstructExpr *consE, ProgramStateRef state, 172 const LocationContext *lctx) 173 : CallE(consE), State(state), LCtx(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 180 bool isFunctionCall() const { 181 return CallE && CallE.is<const CallExpr *>(); 182 } 183 184 bool isCXXConstructExpr() const { 185 return CallE && CallE.is<const CXXConstructExpr *>(); 186 } 187 188 bool isObjCMessage() const { 189 return !CallE; 190 } 191 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. 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 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 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 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 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 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 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. 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