diff options
author | Anna Zaks <ganna@apple.com> | 2013-04-03 19:28:19 +0000 |
---|---|---|
committer | Anna Zaks <ganna@apple.com> | 2013-04-03 19:28:19 +0000 |
commit | 841f16846e17f625874ecfe9c6dba822d29a2b95 (patch) | |
tree | 1eac7cbc5897928b2a4d33be276264c5860439fd | |
parent | cabc3fddae63f5eb3bd44bdecce7a3fbd69421a9 (diff) |
[analyzer] Warn when nil receiver results in forming null reference
This also allows us to ensure IDC/return null suppression gets triggered in such cases.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@178686 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp | 31 | ||||
-rw-r--r-- | test/Analysis/reference.mm | 17 |
2 files changed, 36 insertions, 12 deletions
diff --git a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp index 75c7df8734..4965d22996 100644 --- a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp @@ -366,17 +366,23 @@ void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C, if (!BT_msg_ret) BT_msg_ret.reset( - new BuiltinBug("Receiver in message expression is " - "'nil' and returns a garbage value")); + new BuiltinBug("Receiver in message expression is 'nil'")); const ObjCMessageExpr *ME = msg.getOriginExpr(); + QualType ResTy = msg.getResultType(); + SmallString<200> buf; llvm::raw_svector_ostream os(buf); 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"; + << "' is nil"; + if (ResTy->isReferenceType()) { + os << ", which results in forming a null reference"; + } else { + os << " 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(ME->getReceiverRange()); @@ -419,13 +425,14 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy); const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy); - if (voidPtrSize < returnTypeSize && - !(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) && - (Ctx.FloatTy == CanRetTy || - Ctx.DoubleTy == CanRetTy || - Ctx.LongDoubleTy == CanRetTy || - Ctx.LongLongTy == CanRetTy || - Ctx.UnsignedLongLongTy == CanRetTy))) { + if (CanRetTy.getTypePtr()->isReferenceType()|| + (voidPtrSize < returnTypeSize && + !(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) && + (Ctx.FloatTy == CanRetTy || + Ctx.DoubleTy == CanRetTy || + Ctx.LongDoubleTy == CanRetTy || + Ctx.LongLongTy == CanRetTy || + Ctx.UnsignedLongLongTy == CanRetTy)))) { if (ExplodedNode *N = C.generateSink(state, 0 , &Tag)) emitNilReceiverBug(C, Msg, N); return; diff --git a/test/Analysis/reference.mm b/test/Analysis/reference.mm new file mode 100644 index 0000000000..c5546aac5f --- /dev/null +++ b/test/Analysis/reference.mm @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify -Wno-null-dereference %s + +@interface Foo +- (int &)ref; +@end + +Foo *getFoo() { return 0; } + +void testNullPointerSuppression() { + getFoo().ref = 1; +} + +void testPositiveNullReference() { + Foo *x = 0; + x.ref = 1; // expected-warning {{The receiver of message 'ref' is nil, which results in forming a null reference}} +} + |