aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2008-02-29 23:53:11 +0000
committerTed Kremenek <kremenek@apple.com>2008-02-29 23:53:11 +0000
commit2ded35a576e3899553ea0ccfcbf5cbdb3d8cf664 (patch)
tree55e14a40cc919f0f2d7c1c79fc4397740fa30097
parentbcb2b6112072b071aafb0a7a28f16239c6a006a5 (diff)
Added extra check for calls to functions where we pass undefined values
as arguments. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@47778 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--Analysis/GRExprEngine.cpp28
-rw-r--r--Analysis/GRSimpleVals.cpp5
-rw-r--r--include/clang/Analysis/PathSensitive/GRExprEngine.h13
3 files changed, 42 insertions, 4 deletions
diff --git a/Analysis/GRExprEngine.cpp b/Analysis/GRExprEngine.cpp
index f05dd7acb1..29330da7eb 100644
--- a/Analysis/GRExprEngine.cpp
+++ b/Analysis/GRExprEngine.cpp
@@ -481,12 +481,27 @@ void GRExprEngine::VisitCall(CallExpr* CE, NodeTy* Pred,
NodeSet DstTmp;
Visit(*AI, Pred, DstTmp);
+
if (DstTmp.empty()) DstTmp.Add(Pred);
+ Expr* CurrentArg = *AI;
++AI;
- for (NodeSet::iterator DI=DstTmp.begin(), DE=DstTmp.end(); DI != DE; ++DI)
+ for (NodeSet::iterator DI=DstTmp.begin(), DE=DstTmp.end(); DI != DE; ++DI) {
+ if (GetRVal((*DI)->getState(), CurrentArg).isUndef()) {
+
+ NodeTy* N = Builder->generateNode(CE, (*DI)->getState(), *DI);
+
+ if (N) {
+ N->markAsSink();
+ UndefArgs.insert(N);
+ }
+
+ continue;
+ }
+
VisitCall(CE, *DI, AI, AE, Dst);
+ }
return;
}
@@ -509,8 +524,10 @@ void GRExprEngine::VisitCall(CallExpr* CE, NodeTy* Pred,
if (L.isUndef() || isa<lval::ConcreteInt>(L)) {
NodeTy* N = Builder->generateNode(CE, St, *DI);
- N->markAsSink();
- BadCalls.insert(N);
+ if (N) {
+ N->markAsSink();
+ BadCalls.insert(N);
+ }
continue;
}
@@ -1591,7 +1608,8 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<GRExprEngine::NodeTy*> :
GraphPrintCheckerState->isUndefControlFlow(N) ||
GraphPrintCheckerState->isBadDivide(N) ||
GraphPrintCheckerState->isUndefResult(N) ||
- GraphPrintCheckerState->isBadCall(N))
+ GraphPrintCheckerState->isBadCall(N) ||
+ GraphPrintCheckerState->isUndefArg(N))
return "color=\"red\",style=\"filled\"";
if (GraphPrintCheckerState->isNoReturnCall(N))
@@ -1639,6 +1657,8 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<GRExprEngine::NodeTy*> :
Out << "\\|Call to function marked \"noreturn\".";
else if (GraphPrintCheckerState->isBadCall(N))
Out << "\\|Call to NULL/Undefined.";
+ else if (GraphPrintCheckerState->isUndefArg(N))
+ Out << "\\|Argument in call is undefined";
break;
}
diff --git a/Analysis/GRSimpleVals.cpp b/Analysis/GRSimpleVals.cpp
index d6c133f2dc..a2b6c95d2f 100644
--- a/Analysis/GRSimpleVals.cpp
+++ b/Analysis/GRSimpleVals.cpp
@@ -106,6 +106,11 @@ unsigned RunGRSimpleVals(CFG& cfg, FunctionDecl& FD, ASTContext& Ctx,
CheckerState->bad_calls_begin(),
CheckerState->bad_calls_end(),
"Call using a NULL or undefined function pointer value.");
+
+ EmitWarning(Diag, SrcMgr,
+ CheckerState->undef_arg_begin(),
+ CheckerState->undef_arg_end(),
+ "Pass-by-value argument in function or message expression is undefined.");
#ifndef NDEBUG
if (Visualize) CheckerState->ViewGraph();
diff --git a/include/clang/Analysis/PathSensitive/GRExprEngine.h b/include/clang/Analysis/PathSensitive/GRExprEngine.h
index cd8173ea0d..73fd513191 100644
--- a/include/clang/Analysis/PathSensitive/GRExprEngine.h
+++ b/include/clang/Analysis/PathSensitive/GRExprEngine.h
@@ -91,6 +91,7 @@ protected:
typedef llvm::SmallPtrSet<NodeTy*,2> UndefStoresTy;
typedef llvm::SmallPtrSet<NodeTy*,2> BadDerefTy;
typedef llvm::SmallPtrSet<NodeTy*,2> BadCallsTy;
+ typedef llvm::SmallPtrSet<NodeTy*,2> UndefArgsTy;
typedef llvm::SmallPtrSet<NodeTy*,2> BadDividesTy;
typedef llvm::SmallPtrSet<NodeTy*,2> NoReturnCallsTy;
typedef llvm::SmallPtrSet<NodeTy*,2> UndefResultsTy;
@@ -132,6 +133,10 @@ protected:
/// pointers that are NULL (or other constants) or Undefined.
BadCallsTy BadCalls;
+ /// UndefArg - Nodes in the ExplodedGraph resulting from calls to functions
+ /// where a pass-by-value argument has an undefined value.
+ UndefArgsTy UndefArgs;
+
bool StateCleaned;
public:
@@ -203,6 +208,10 @@ public:
return N->isSink() && BadCalls.count(const_cast<NodeTy*>(N)) != 0;
}
+ bool isUndefArg(const NodeTy* N) const {
+ return N->isSink() && UndefArgs.count(const_cast<NodeTy*>(N)) != 0;
+ }
+
typedef BadDerefTy::iterator null_deref_iterator;
null_deref_iterator null_derefs_begin() { return ExplicitNullDeref.begin(); }
null_deref_iterator null_derefs_end() { return ExplicitNullDeref.end(); }
@@ -223,6 +232,10 @@ public:
bad_calls_iterator bad_calls_begin() { return BadCalls.begin(); }
bad_calls_iterator bad_calls_end() { return BadCalls.end(); }
+ typedef UndefArgsTy::iterator undef_arg_iterator;
+ undef_arg_iterator undef_arg_begin() { return UndefArgs.begin(); }
+ undef_arg_iterator undef_arg_end() { return UndefArgs.end(); }
+
/// ProcessStmt - Called by GRCoreEngine. Used to generate new successor
/// nodes by processing the 'effects' of a block-level statement.
void ProcessStmt(Stmt* S, StmtNodeBuilder& builder);