aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp')
-rw-r--r--lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp106
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));