diff options
Diffstat (limited to 'lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp | 106 |
1 files changed, 67 insertions, 39 deletions
diff --git a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp index 69b331c16c..17ed692a6c 100644 --- a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp @@ -34,6 +34,7 @@ class CallAndMessageChecker mutable OwningPtr<BugType> BT_call_arg; mutable OwningPtr<BugType> BT_msg_undef; mutable OwningPtr<BugType> BT_objc_prop_undef; + mutable OwningPtr<BugType> BT_objc_subscript_undef; mutable OwningPtr<BugType> BT_msg_arg; mutable OwningPtr<BugType> BT_msg_ret; public: @@ -45,8 +46,8 @@ public: private: static bool PreVisitProcessArg(CheckerContext &C, SVal V, SourceRange argRange, const Expr *argEx, - const bool checkUninitFields, - const char *BT_desc, OwningPtr<BugType> &BT); + bool IsFirstArgument, bool checkUninitFields, + const CallEvent &Call, OwningPtr<BugType> &BT); static void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE); void emitNilReceiverBug(CheckerContext &C, const ObjCMethodCall &msg, @@ -75,18 +76,46 @@ void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C, C.EmitReport(R); } +StringRef describeUninitializedArgumentInCall(const CallEvent &Call, + bool IsFirstArgument) { + switch (Call.getKind()) { + case CE_ObjCMessage: { + const ObjCMethodCall &Msg = cast<ObjCMethodCall>(Call); + switch (Msg.getMessageKind()) { + case OCM_Message: + return "Argument in message expression is an uninitialized value"; + case OCM_PropertyAccess: + assert(Msg.isSetter() && "Getters have no args"); + return "Argument for property setter is an uninitialized value"; + case OCM_Subscript: + if (Msg.isSetter() && IsFirstArgument) + return "Argument for subscript setter is an uninitialized value"; + return "Subscript index is an uninitialized value"; + } + llvm_unreachable("Unknown message kind."); + } + case CE_Block: + return "Block call argument is an uninitialized value"; + default: + return "Function call argument is an uninitialized value"; + } +} + bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, SVal V, SourceRange argRange, const Expr *argEx, - const bool checkUninitFields, - const char *BT_desc, + bool IsFirstArgument, + bool checkUninitFields, + const CallEvent &Call, OwningPtr<BugType> &BT) { if (V.isUndef()) { if (ExplodedNode *N = C.generateSink()) { LazyInit_BT("Uninitialized argument value", BT); // Generate a report for this bug. - BugReport *R = new BugReport(*BT, BT_desc, N); + StringRef Desc = describeUninitializedArgumentInCall(Call, + IsFirstArgument); + BugReport *R = new BugReport(*BT, Desc, N); R->addRange(argRange); if (argEx) R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, argEx, @@ -148,7 +177,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, if (F.Find(D->getRegion())) { if (ExplodedNode *N = C.generateSink()) { - LazyInit_BT(BT_desc, BT); + LazyInit_BT("Uninitialized argument value", BT); SmallString<512> Str; llvm::raw_svector_ostream os(Str); os << "Passed-by-value struct argument contains uninitialized data"; @@ -220,32 +249,15 @@ void CallAndMessageChecker::checkPreCall(const CallEvent &Call, (D && D->getBody())); OwningPtr<BugType> *BT; - const char *Desc; - - switch (Call.getKind()) { - case CE_ObjCPropertyAccess: - BT = &BT_msg_arg; - // Getters do not have arguments, so we don't need to worry about this. - Desc = "Argument for property setter is an uninitialized value"; - break; - case CE_ObjCMessage: + if (isa<ObjCMethodCall>(Call)) BT = &BT_msg_arg; - Desc = "Argument in message expression is an uninitialized value"; - break; - case CE_Block: + else BT = &BT_call_arg; - Desc = "Block call argument is an uninitialized value"; - break; - default: - BT = &BT_call_arg; - Desc = "Function call argument is an uninitialized value"; - break; - } for (unsigned i = 0, e = Call.getNumArgs(); i != e; ++i) - if (PreVisitProcessArg(C, Call.getArgSVal(i), - Call.getArgSourceRange(i), Call.getArgExpr(i), - checkUninitFields, Desc, *BT)) + if (PreVisitProcessArg(C, Call.getArgSVal(i), Call.getArgSourceRange(i), + Call.getArgExpr(i), /*IsFirstArgument=*/i == 0, + checkUninitFields, Call, *BT)) return; } @@ -255,22 +267,36 @@ void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg, if (recVal.isUndef()) { if (ExplodedNode *N = C.generateSink()) { BugType *BT = 0; - if (isa<ObjCPropertyAccess>(msg)) { - if (!BT_objc_prop_undef) - BT_objc_prop_undef.reset(new BuiltinBug("Property access on an " - "uninitialized object pointer")); - BT = BT_objc_prop_undef.get(); - } else { + switch (msg.getMessageKind()) { + case OCM_Message: if (!BT_msg_undef) BT_msg_undef.reset(new BuiltinBug("Receiver in message expression " "is an uninitialized value")); BT = BT_msg_undef.get(); + break; + case OCM_PropertyAccess: + if (!BT_objc_prop_undef) + BT_objc_prop_undef.reset(new BuiltinBug("Property access on an " + "uninitialized object " + "pointer")); + BT = BT_objc_prop_undef.get(); + break; + case OCM_Subscript: + if (!BT_objc_subscript_undef) + BT_objc_subscript_undef.reset(new BuiltinBug("Subscript access on an " + "uninitialized object " + "pointer")); + BT = BT_objc_subscript_undef.get(); + break; } + assert(BT && "Unknown message kind."); + BugReport *R = new BugReport(*BT, BT->getName(), N); - R->addRange(msg.getReceiverSourceRange()); + const ObjCMessageExpr *ME = msg.getOriginExpr(); + R->addRange(ME->getReceiverRange()); // FIXME: getTrackNullOrUndefValueVisitor can't handle "super" yet. - if (const Expr *ReceiverE = msg.getInstanceReceiverExpr()) + if (const Expr *ReceiverE = ME->getInstanceReceiver()) R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, ReceiverE, R)); @@ -302,17 +328,19 @@ void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C, new BuiltinBug("Receiver in message expression is " "'nil' and returns a garbage value")); + const ObjCMessageExpr *ME = msg.getOriginExpr(); + SmallString<200> buf; llvm::raw_svector_ostream os(buf); - os << "The receiver of message '" << msg.getSelector().getAsString() + os << "The receiver of message '" << ME->getSelector().getAsString() << "' is nil and returns a value of type '"; msg.getResultType().print(os, C.getLangOpts()); os << "' that will be garbage"; BugReport *report = new BugReport(*BT_msg_ret, os.str(), N); - report->addRange(msg.getReceiverSourceRange()); + report->addRange(ME->getReceiverRange()); // FIXME: This won't track "self" in messages to super. - if (const Expr *receiver = msg.getInstanceReceiverExpr()) { + if (const Expr *receiver = ME->getInstanceReceiver()) { report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, receiver, report)); |