summaryrefslogtreecommitdiffstats
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.cpp61
1 files changed, 37 insertions, 24 deletions
diff --git a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index 82bc136..4965d22 100644
--- a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
@@ -13,14 +13,15 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/ParentMap.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/AST/ParentMap.h"
-#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -75,6 +76,8 @@ void CallAndMessageChecker::emitBadCall(BugType *BT, CheckerContext &C,
BugReport *R = new BugReport(*BT, BT->getName(), N);
if (BadE) {
R->addRange(BadE->getSourceRange());
+ if (BadE->isGLValue())
+ BadE = bugreporter::getDerefExpr(BadE);
bugreporter::trackNullOrUndefValue(N, BadE, *R);
}
C.emitReport(R);
@@ -130,9 +133,9 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
if (!checkUninitFields)
return false;
-
- if (const nonloc::LazyCompoundVal *LV =
- dyn_cast<nonloc::LazyCompoundVal>(&V)) {
+
+ if (Optional<nonloc::LazyCompoundVal> LV =
+ V.getAs<nonloc::LazyCompoundVal>()) {
class FindUninitializedField {
public:
@@ -233,7 +236,8 @@ void CallAndMessageChecker::checkPreStmt(const CallExpr *CE,
}
ProgramStateRef StNonNull, StNull;
- llvm::tie(StNonNull, StNull) = State->assume(cast<DefinedOrUnknownSVal>(L));
+ llvm::tie(StNonNull, StNull) =
+ State->assume(L.castAs<DefinedOrUnknownSVal>());
if (StNull && !StNonNull) {
if (!BT_call_null)
@@ -262,7 +266,8 @@ void CallAndMessageChecker::checkPreCall(const CallEvent &Call,
}
ProgramStateRef StNonNull, StNull;
- llvm::tie(StNonNull, StNull) = State->assume(cast<DefinedOrUnknownSVal>(V));
+ llvm::tie(StNonNull, StNull) =
+ State->assume(V.castAs<DefinedOrUnknownSVal>());
if (StNull && !StNonNull) {
if (!BT_cxx_call_null)
@@ -341,7 +346,7 @@ void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
return;
} else {
// Bifurcate the state into nil and non-nil ones.
- DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal);
+ DefinedOrUnknownSVal receiverVal = recVal.castAs<DefinedOrUnknownSVal>();
ProgramStateRef state = C.getState();
ProgramStateRef notNilState, nilState;
@@ -361,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());
@@ -392,6 +403,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
ProgramStateRef state,
const ObjCMethodCall &Msg) const {
ASTContext &Ctx = C.getASTContext();
+ static SimpleProgramPointTag Tag("CallAndMessageChecker : NilReceiver");
// Check the return type of the message expression. A message to nil will
// return different values depending on the return type and the architecture.
@@ -402,7 +414,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
if (CanRetTy->isStructureOrClassType()) {
// Structure returns are safe since the compiler zeroes them out.
SVal V = C.getSValBuilder().makeZeroVal(RetTy);
- C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V));
+ C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag);
return;
}
@@ -413,14 +425,15 @@ 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 (ExplodedNode *N = C.generateSink(state))
+ 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;
}
@@ -439,7 +452,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
// of this case unless we have *a lot* more knowledge.
//
SVal V = C.getSValBuilder().makeZeroVal(RetTy);
- C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V));
+ C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag);
return;
}
OpenPOWER on IntegriCloud