From: Ted Kremenek Date: Fri, 29 Feb 2008 23:14:48 +0000 (+0000) Subject: Add checks for function calls via a function pointer that is NULL, Undefined, X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5e03fcb5420c33207433dd6f800588e256dd9bdb;p=clang Add checks for function calls via a function pointer that is NULL, Undefined, or otherwise a constant integer value that doesn't evaluate to an address. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@47774 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Analysis/GRExprEngine.cpp b/Analysis/GRExprEngine.cpp index 2b94b4fafa..f05dd7acb1 100644 --- a/Analysis/GRExprEngine.cpp +++ b/Analysis/GRExprEngine.cpp @@ -507,11 +507,10 @@ void GRExprEngine::VisitCall(CallExpr* CE, NodeTy* Pred, // Check for undefined control-flow. - if (L.isUndef()) { - + if (L.isUndef() || isa(L)) { NodeTy* N = Builder->generateNode(CE, St, *DI); N->markAsSink(); - UndefBranches.insert(N); + BadCalls.insert(N); continue; } @@ -1591,7 +1590,8 @@ struct VISIBILITY_HIDDEN DOTGraphTraits : GraphPrintCheckerState->isUndefStore(N) || GraphPrintCheckerState->isUndefControlFlow(N) || GraphPrintCheckerState->isBadDivide(N) || - GraphPrintCheckerState->isUndefResult(N)) + GraphPrintCheckerState->isUndefResult(N) || + GraphPrintCheckerState->isBadCall(N)) return "color=\"red\",style=\"filled\""; if (GraphPrintCheckerState->isNoReturnCall(N)) @@ -1623,26 +1623,22 @@ struct VISIBILITY_HIDDEN DOTGraphTraits : L.getStmt()->printPretty(Out); - if (GraphPrintCheckerState->isImplicitNullDeref(N)) { + if (GraphPrintCheckerState->isImplicitNullDeref(N)) Out << "\\|Implicit-Null Dereference.\\l"; - } - else if (GraphPrintCheckerState->isExplicitNullDeref(N)) { + else if (GraphPrintCheckerState->isExplicitNullDeref(N)) Out << "\\|Explicit-Null Dereference.\\l"; - } - else if (GraphPrintCheckerState->isUndefDeref(N)) { + else if (GraphPrintCheckerState->isUndefDeref(N)) Out << "\\|Dereference of undefialied value.\\l"; - } - else if (GraphPrintCheckerState->isUndefStore(N)) { + else if (GraphPrintCheckerState->isUndefStore(N)) Out << "\\|Store to Undefined LVal."; - } - else if (GraphPrintCheckerState->isBadDivide(N)) { + else if (GraphPrintCheckerState->isBadDivide(N)) Out << "\\|Divide-by zero or undefined value."; - } - else if (GraphPrintCheckerState->isUndefResult(N)) { + else if (GraphPrintCheckerState->isUndefResult(N)) Out << "\\|Result of operation is undefined."; - } else if (GraphPrintCheckerState->isNoReturnCall(N)) Out << "\\|Call to function marked \"noreturn\"."; + else if (GraphPrintCheckerState->isBadCall(N)) + Out << "\\|Call to NULL/Undefined."; break; } diff --git a/Analysis/GRSimpleVals.cpp b/Analysis/GRSimpleVals.cpp index 366ffb70c6..d6c133f2dc 100644 --- a/Analysis/GRSimpleVals.cpp +++ b/Analysis/GRSimpleVals.cpp @@ -101,6 +101,11 @@ unsigned RunGRSimpleVals(CFG& cfg, FunctionDecl& FD, ASTContext& Ctx, CheckerState->undef_results_begin(), CheckerState->undef_results_end(), "Result of operation is undefined."); + + EmitWarning(Diag, SrcMgr, + CheckerState->bad_calls_begin(), + CheckerState->bad_calls_end(), + "Call using a NULL or undefined function pointer value."); #ifndef NDEBUG if (Visualize) CheckerState->ViewGraph(); diff --git a/include/clang/Analysis/PathSensitive/GRExprEngine.h b/include/clang/Analysis/PathSensitive/GRExprEngine.h index b4751666b2..cd8173ea0d 100644 --- a/include/clang/Analysis/PathSensitive/GRExprEngine.h +++ b/include/clang/Analysis/PathSensitive/GRExprEngine.h @@ -90,6 +90,7 @@ protected: typedef llvm::SmallPtrSet UndefBranchesTy; typedef llvm::SmallPtrSet UndefStoresTy; typedef llvm::SmallPtrSet BadDerefTy; + typedef llvm::SmallPtrSet BadCallsTy; typedef llvm::SmallPtrSet BadDividesTy; typedef llvm::SmallPtrSet NoReturnCallsTy; typedef llvm::SmallPtrSet UndefResultsTy; @@ -127,6 +128,10 @@ protected: /// by the result is not. Excludes divide-by-zero errors. UndefResultsTy UndefResults; + /// BadCalls - Nodes in the ExplodedGraph resulting from calls to function + /// pointers that are NULL (or other constants) or Undefined. + BadCallsTy BadCalls; + bool StateCleaned; public: @@ -194,6 +199,10 @@ public: return N->isSink() && UndefResults.count(const_cast(N)) != 0; } + bool isBadCall(const NodeTy* N) const { + return N->isSink() && BadCalls.count(const_cast(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(); } @@ -209,6 +218,10 @@ public: typedef UndefResultsTy::iterator undef_result_iterator; undef_result_iterator undef_results_begin() { return UndefResults.begin(); } undef_result_iterator undef_results_end() { return UndefResults.end(); } + + typedef BadCallsTy::iterator bad_calls_iterator; + bad_calls_iterator bad_calls_begin() { return BadCalls.begin(); } + bad_calls_iterator bad_calls_end() { return BadCalls.end(); } /// ProcessStmt - Called by GRCoreEngine. Used to generate new successor /// nodes by processing the 'effects' of a block-level statement.