diff options
-rw-r--r-- | clang/include/clang/Analysis/PathSensitive/GRExprEngine.h | 20 | ||||
-rw-r--r-- | clang/lib/Analysis/GRExprEngine.cpp | 30 | ||||
-rw-r--r-- | clang/lib/Analysis/GRExprEngineInternalChecks.cpp | 32 |
3 files changed, 79 insertions, 3 deletions
diff --git a/clang/include/clang/Analysis/PathSensitive/GRExprEngine.h b/clang/include/clang/Analysis/PathSensitive/GRExprEngine.h index c2ff5330e4e..7f2b5f595b8 100644 --- a/clang/include/clang/Analysis/PathSensitive/GRExprEngine.h +++ b/clang/include/clang/Analysis/PathSensitive/GRExprEngine.h @@ -94,6 +94,16 @@ public: typedef llvm::SmallPtrSet<NodeTy*,2> ErrorNodes; typedef llvm::DenseMap<NodeTy*, Expr*> UndefArgsTy; + /// NilReceiverStructRetExplicit - Nodes in the ExplodedGraph that resulted + /// from [x ...] with 'x' definitely being nil and the result was a 'struct' + // (an undefined value). + ErrorNodes NilReceiverStructRetExplicit; + + /// NilReceiverStructRetImplicit - Nodes in the ExplodedGraph that resulted + /// from [x ...] with 'x' possibly being nil and the result was a 'struct' + // (an undefined value). + ErrorNodes NilReceiverStructRetImplicit; + /// RetsStackAddr - Nodes in the ExplodedGraph that result from returning /// the address of a stack variable. ErrorNodes RetsStackAddr; @@ -300,6 +310,16 @@ public: return ImplicitNullDeref.end(); } + typedef ErrorNodes::iterator nil_receiver_struct_ret_iterator; + + nil_receiver_struct_ret_iterator nil_receiver_struct_ret_begin() { + return NilReceiverStructRetExplicit.begin(); + } + + nil_receiver_struct_ret_iterator nil_receiver_struct_ret_end() { + return NilReceiverStructRetExplicit.end(); + } + typedef ErrorNodes::iterator undef_deref_iterator; undef_deref_iterator undef_derefs_begin() { return UndefDeref.begin(); } undef_deref_iterator undef_derefs_end() { return UndefDeref.end(); } diff --git a/clang/lib/Analysis/GRExprEngine.cpp b/clang/lib/Analysis/GRExprEngine.cpp index b0554151825..60bef6eb718 100644 --- a/clang/lib/Analysis/GRExprEngine.cpp +++ b/clang/lib/Analysis/GRExprEngine.cpp @@ -1514,8 +1514,7 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, SVal L = GetSVal(state, Receiver); - // Check for undefined control-flow or calls to NULL. - + // Check for undefined control-flow. if (L.isUndef()) { NodeTy* N = Builder->generateNode(ME, state, Pred); @@ -1527,6 +1526,33 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, return; } + // "Assume" that the receiver is not NULL. + bool isFeasibleNotNull = false; + Assume(state, L, true, isFeasibleNotNull); + + // "Assume" that the receiver is NULL. + bool isFeasibleNull = false; + const GRState *StNull = Assume(state, L, false, isFeasibleNull); + + if (isFeasibleNull) { + // Check if the receiver was nil and the return value a struct. + if (ME->getType()->isRecordType()) { + // The [0 ...] expressions will return garbage. Flag either an + // explicit or implicit error. Because of the structure of this + // function we currently do not bifurfacte the state graph at + // this point. + // FIXME: We should bifurcate and fill the returned struct with + // garbage. + if (NodeTy* N = Builder->generateNode(ME, StNull, Pred)) { + N->markAsSink(); + if (isFeasibleNotNull) + NilReceiverStructRetImplicit.insert(N); + else + NilReceiverStructRetExplicit.insert(N); + } + } + } + // Check if the "raise" message was sent. if (ME->getSelector() == RaiseSel) RaisesException = true; diff --git a/clang/lib/Analysis/GRExprEngineInternalChecks.cpp b/clang/lib/Analysis/GRExprEngineInternalChecks.cpp index b7762d8412b..135f746ba1c 100644 --- a/clang/lib/Analysis/GRExprEngineInternalChecks.cpp +++ b/clang/lib/Analysis/GRExprEngineInternalChecks.cpp @@ -71,6 +71,34 @@ public: } }; +class VISIBILITY_HIDDEN NilReceiverStructRet : public BugType { + GRExprEngine &Eng; +public: + NilReceiverStructRet(GRExprEngine* eng) : + BugType("nil receiver with struct return type", "Logic Errors"), + Eng(*eng) {} + + void FlushReports(BugReporter& BR) { + for (GRExprEngine::nil_receiver_struct_ret_iterator + I=Eng.nil_receiver_struct_ret_begin(), + E=Eng.nil_receiver_struct_ret_end(); I!=E; ++I) { + + std::string sbuf; + llvm::raw_string_ostream os(sbuf); + PostStmt P = cast<PostStmt>((*I)->getLocation()); + ObjCMessageExpr *ME = cast<ObjCMessageExpr>(P.getStmt()); + os << "The receiver in the message expression is 'nil' and results in the" + " returned value (of type '" + << ME->getType().getAsString() + << "') to be garbage or otherwise undefined."; + + RangedBugReport *R = new RangedBugReport(*this, os.str().c_str(), *I); + R->addRange(ME->getReceiver()->getSourceRange()); + BR.EmitReport(R); + } + } +}; + class VISIBILITY_HIDDEN UndefinedDeref : public BuiltinBug { public: UndefinedDeref(GRExprEngine* eng) @@ -142,7 +170,8 @@ public: for (GRExprEngine::UndefArgsTy::iterator I=Eng.msg_expr_undef_arg_begin(), E = Eng.msg_expr_undef_arg_end(); I!=E; ++I) { // Generate a report for this bug. - RangedBugReport *report = new RangedBugReport(*this, desc.c_str(), I->first); + RangedBugReport *report = new RangedBugReport(*this, desc.c_str(), + I->first); report->addRange(I->second->getSourceRange()); BR.EmitReport(report); } @@ -431,6 +460,7 @@ void GRExprEngine::RegisterInternalChecks() { BR.Register(new BadReceiver(this)); BR.Register(new OutOfBoundMemoryAccess(this)); BR.Register(new BadSizeVLA(this)); + BR.Register(new NilReceiverStructRet(this)); // The following checks do not need to have their associated BugTypes // explicitly registered with the BugReporter. If they issue any BugReports, |