[cfe-commits] r159692 - in /cfe/trunk: include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp lib/StaticAnalyzer/Core/Calls.cpp lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp test/Analysis/operator-calls.cpp
Jordan Rose
jordan_rose at apple.com
Tue Jul 3 15:55:57 PDT 2012
Author: jrose
Date: Tue Jul 3 17:55:57 2012
New Revision: 159692
URL: http://llvm.org/viewvc/llvm-project?rev=159692&view=rev
Log:
[analyzer] For now, don't inline non-static member overloaded operators.
Our current inlining support (specifically RegionStore::enterStackFrame)
doesn't know that calls to overloaded operators may be calls to non-static
member functions, and that in these cases the first argument should be
treated as 'this'. This caused incorrect results and sometimes crashes.
The long-term fix will be to rewrite RegionStore::enterStackFrame to use
CallEvent and its subclasses, but for now we can just disable these
problematic calls by classifying them under a new CallEvent,
CXXMemberOperatorCall.
Modified:
cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h
cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
cfe/trunk/lib/StaticAnalyzer/Core/Calls.cpp
cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
cfe/trunk/test/Analysis/operator-calls.cpp
Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h?rev=159692&r1=159691&r2=159692&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h Tue Jul 3 17:55:57 2012
@@ -29,6 +29,7 @@
enum CallEventKind {
CE_Function,
CE_CXXMember,
+ CE_CXXMemberOperator,
CE_Block,
CE_BEG_SIMPLE_CALLS = CE_Function,
CE_END_SIMPLE_CALLS = CE_Block,
@@ -264,9 +265,36 @@
}
};
+/// \brief Represents a C++ overloaded operator call where the operator is
+/// implemented as a non-static member function.
+///
+/// Example: <tt>iter + 1</tt>
+class CXXMemberOperatorCall : public SimpleCall {
+protected:
+ void addExtraInvalidatedRegions(RegionList &Regions) const;
+
+public:
+ CXXMemberOperatorCall(const CXXOperatorCallExpr *CE, ProgramStateRef St,
+ const LocationContext *LCtx)
+ : SimpleCall(CE, St, LCtx, CE_CXXMemberOperator) {}
+
+ const CXXOperatorCallExpr *getOriginExpr() const {
+ return cast<CXXOperatorCallExpr>(SimpleCall::getOriginExpr());
+ }
+
+ unsigned getNumArgs() const { return getOriginExpr()->getNumArgs() - 1; }
+ const Expr *getArgExpr(unsigned Index) const {
+ return getOriginExpr()->getArg(Index + 1);
+ }
+
+ static bool classof(const CallEvent *CA) {
+ return CA->getKind() == CE_CXXMemberOperator;
+ }
+};
+
/// \brief Represents a call to a block.
///
-/// Example: \c ^{ /* ... */ }()
+/// Example: <tt>^{ /* ... */ }()</tt>
class BlockCall : public SimpleCall {
protected:
void addExtraInvalidatedRegions(RegionList &Regions) const;
Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp?rev=159692&r1=159691&r2=159692&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp Tue Jul 3 17:55:57 2012
@@ -945,6 +945,7 @@
Summ = getFunctionSummary(cast<FunctionCall>(Call).getDecl());
break;
case CE_CXXMember:
+ case CE_CXXMemberOperator:
case CE_Block:
case CE_CXXConstructor:
case CE_CXXAllocator:
Modified: cfe/trunk/lib/StaticAnalyzer/Core/Calls.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/Calls.cpp?rev=159692&r1=159691&r2=159692&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/Calls.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/Calls.cpp Tue Jul 3 17:55:57 2012
@@ -303,6 +303,14 @@
}
+void
+CXXMemberOperatorCall::addExtraInvalidatedRegions(RegionList &Regions) const {
+ const Expr *Base = getOriginExpr()->getArg(0);
+ if (const MemRegion *R = getSVal(Base).getAsRegion())
+ Regions.push_back(R);
+}
+
+
const BlockDataRegion *BlockCall::getBlockRegion() const {
const Expr *Callee = getOriginExpr()->getCallee();
const MemRegion *DataReg = getSVal(Callee).getAsRegion();
Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp?rev=159692&r1=159691&r2=159692&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp Tue Jul 3 17:55:57 2012
@@ -22,6 +22,23 @@
using namespace clang;
using namespace ento;
+static CallEventKind classifyCallExpr(const CallExpr *CE) {
+ if (isa<CXXMemberCallExpr>(CE))
+ return CE_CXXMember;
+
+ const CXXOperatorCallExpr *OpCE = dyn_cast<CXXOperatorCallExpr>(CE);
+ if (OpCE) {
+ const FunctionDecl *DirectCallee = CE->getDirectCallee();
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DirectCallee))
+ if (MD->isInstance())
+ return CE_CXXMemberOperator;
+ } else if (CE->getCallee()->getType()->isBlockPointerType()) {
+ return CE_Block;
+ }
+
+ return CE_Function;
+}
+
void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) {
// Get the entry block in the CFG of the callee.
const StackFrameContext *calleeCtx = CE.getCalleeContext();
@@ -265,6 +282,12 @@
case CE_CXXMember:
// These are always at least possible to inline.
break;
+ case CE_CXXMemberOperator:
+ // FIXME: This should be possible to inline, but
+ // RegionStore::enterStackFrame isn't smart enough to handle the first
+ // argument being 'this'. The correct solution is to use CallEvent in
+ // enterStackFrame as well.
+ return false;
case CE_CXXConstructor:
// Do not inline constructors until we can model destructors.
// This is unfortunate, but basically necessary for smart pointers and such.
@@ -336,9 +359,7 @@
getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, CE, *this);
// Get the callee kind.
- const CXXMemberCallExpr *MemberCE = dyn_cast<CXXMemberCallExpr>(CE);
- bool IsBlock = (MemberCE ? false
- : CE->getCallee()->getType()->isBlockPointerType());
+ CallEventKind K = classifyCallExpr(CE);
// Evaluate the function call. We try each of the checkers
// to see if the can evaluate the function call.
@@ -349,12 +370,25 @@
const LocationContext *LCtx = (*I)->getLocationContext();
// Evaluate the call.
- if (MemberCE)
- evalCall(dstCallEvaluated, *I, CXXMemberCall(MemberCE, State, LCtx));
- else if (IsBlock)
- evalCall(dstCallEvaluated, *I, BlockCall(CE, State, LCtx));
- else
+ switch (K) {
+ case CE_Function:
evalCall(dstCallEvaluated, *I, FunctionCall(CE, State, LCtx));
+ break;
+ case CE_CXXMember:
+ evalCall(dstCallEvaluated, *I, CXXMemberCall(cast<CXXMemberCallExpr>(CE),
+ State, LCtx));
+ break;
+ case CE_CXXMemberOperator:
+ evalCall(dstCallEvaluated, *I,
+ CXXMemberOperatorCall(cast<CXXOperatorCallExpr>(CE),
+ State, LCtx));
+ break;
+ case CE_Block:
+ evalCall(dstCallEvaluated, *I, BlockCall(CE, State, LCtx));
+ break;
+ default:
+ llvm_unreachable("Non-CallExpr CallEventKind");
+ }
}
// Finally, perform the post-condition check of the CallExpr and store
Modified: cfe/trunk/test/Analysis/operator-calls.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/operator-calls.cpp?rev=159692&r1=159691&r2=159692&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/operator-calls.cpp (original)
+++ cfe/trunk/test/Analysis/operator-calls.cpp Tue Jul 3 17:55:57 2012
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core,debug.ExprInspection -verify %s
+void clang_analyzer_eval(bool);
+
struct X0 { };
bool operator==(const X0&, const X0&);
@@ -14,3 +16,18 @@
bool PR7287(X0 a, X0 b) {
return operator==(a, b);
}
+
+
+// Inlining non-static member operators mistakenly treated 'this' as the first
+// argument for a while.
+
+struct IntComparable {
+ bool operator==(int x) const {
+ return x == 0;
+ }
+};
+
+void testMemberOperator(IntComparable B) {
+ // FIXME: Change this to TRUE when we re-enable inlining.
+ clang_analyzer_eval(B == 0); // expected-warning{{UNKNOWN}}
+}
More information about the cfe-commits
mailing list