From: Ted Kremenek Date: Fri, 18 Dec 2009 20:13:39 +0000 (+0000) Subject: Enhance GRExprEngine::VisitCallExpr() to be used in an lvalue context. Uncovered... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=53287518f69b8f06f82a6cdbd13e4e3a13b58186;p=clang Enhance GRExprEngine::VisitCallExpr() to be used in an lvalue context. Uncovered a new failing test case along the way, but we're making progress on handling C++ references in the analyzer. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@91710 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Analysis/PathSensitive/GRExprEngine.h b/include/clang/Analysis/PathSensitive/GRExprEngine.h index 6c422edff9..21031a488e 100644 --- a/include/clang/Analysis/PathSensitive/GRExprEngine.h +++ b/include/clang/Analysis/PathSensitive/GRExprEngine.h @@ -265,7 +265,7 @@ protected: /// VisitCall - Transfer function for function calls. void VisitCall(CallExpr* CE, ExplodedNode* Pred, CallExpr::arg_iterator AI, CallExpr::arg_iterator AE, - ExplodedNodeSet& Dst); + ExplodedNodeSet& Dst, bool asLValue); /// VisitCast - Transfer function logic for all casts (implicit and explicit). void VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred, diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index 9b00d1e64a..4295e9a1ae 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -46,6 +46,23 @@ static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) { return Ctx.Selectors.getSelector(0, &II); } +static bool CalleeReturnsReference(const CallExpr *CE) { + const Expr *Callee = CE->getCallee(); + QualType T = Callee->getType(); + + + if (const PointerType *PT = T->getAs()) { + const FunctionType *FT = PT->getPointeeType()->getAs(); + T = FT->getResultType(); + } + else { + const BlockPointerType *BT = T->getAs(); + T = BT->getPointeeType()->getAs()->getResultType(); + } + + return T->isReferenceType(); +} + //===----------------------------------------------------------------------===// // Batch auditor. DEPRECATED. //===----------------------------------------------------------------------===// @@ -228,7 +245,7 @@ void GRExprEngine::CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE, CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp; CurrSet->clear(); } - + void *tag = I->first; Checker *checker = I->second; @@ -593,7 +610,7 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { case Stmt::CallExprClass: case Stmt::CXXOperatorCallExprClass: { CallExpr* C = cast(S); - VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst); + VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst, false); break; } @@ -745,6 +762,14 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, VisitBlockDeclRefExpr(cast(Ex), Pred, Dst, true); return; + case Stmt::CallExprClass: + case Stmt::CXXOperatorCallExprClass: { + CallExpr* C = cast(Ex); + assert(CalleeReturnsReference(C)); + VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst, true); + break; + } + case Stmt::CompoundLiteralExprClass: VisitCompoundLiteralExpr(cast(Ex), Pred, Dst, true); return; @@ -1563,7 +1588,7 @@ public: void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred, CallExpr::arg_iterator AI, CallExpr::arg_iterator AE, - ExplodedNodeSet& Dst) { + ExplodedNodeSet& Dst, bool asLValue) { // Determine the type of function we're calling (if available). const FunctionProtoType *Proto = NULL; @@ -1577,7 +1602,7 @@ void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred, WorkList.push_back(CallExprWLItem(AI, Pred)); ExplodedNodeSet ArgsEvaluated; - + while (!WorkList.empty()) { CallExprWLItem Item = WorkList.back(); WorkList.pop_back(); @@ -1623,6 +1648,7 @@ void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred, // Finally, evaluate the function call. We try each of the checkers // to see if the can evaluate the function call. ExplodedNodeSet DstTmp3; + for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end(); DI != DE; ++DI) { @@ -1664,7 +1690,28 @@ void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred, // Finally, perform the post-condition check of the CallExpr and store // the created nodes in 'Dst'. - CheckerVisit(CE, Dst, DstTmp3, false); + + if (!(!asLValue && CalleeReturnsReference(CE))) { + CheckerVisit(CE, Dst, DstTmp3, false); + return; + } + + // Handle the case where the called function returns a reference but + // we expect an rvalue. For such cases, convert the reference to + // an rvalue. + // FIXME: This conversion doesn't actually happen unless the result + // of CallExpr is consumed by another expression. + ExplodedNodeSet DstTmp4; + CheckerVisit(CE, DstTmp4, DstTmp3, false); + QualType LoadTy = CE->getType(); + + static int *ConvertToRvalueTag = 0; + for (ExplodedNodeSet::iterator NI = DstTmp4.begin(), NE = DstTmp4.end(); + NI!=NE; ++NI) { + const GRState *state = GetState(*NI); + EvalLoad(Dst, CE, *NI, state, state->getSVal(CE), + &ConvertToRvalueTag, LoadTy); + } } //===----------------------------------------------------------------------===// diff --git a/test/Analysis/misc-ps-region-store.cpp b/test/Analysis/misc-ps-region-store.cpp index c1e03bb0d9..838ac39d5c 100644 --- a/test/Analysis/misc-ps-region-store.cpp +++ b/test/Analysis/misc-ps-region-store.cpp @@ -2,8 +2,14 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s // XFAIL: * -// This test case currently crashes because of an assertion failure. +// Test basic handling of references. char &test1_aux(); char *test1() { return &test1_aux(); } + +// This test currently crasehs because test1_aux() evaluates to a 'char' instead of a char& in CFRefCount.cpp. +char test1_as_rvalue() { + return test1_aux(); +} +