From c297ed8204a1d6472b9eff90b6aa1029aea932d8 Mon Sep 17 00:00:00 2001 From: Ken-Patrick Lehrmann Date: Wed, 17 Jun 2020 19:01:32 +0200 Subject: [PATCH] Better handle noreturn or throwing functions in valueflow Teaching cppcheck about `BOOST_THROW_EXCEPTION` and `boost::throw_exception`, and using noreturn information from libraries in value flow. This fixes false positive nullPointerRedundantCheck with the following code: ``` void throwexception(int * buf) { if (!buf) boost::throw_exception(std::bad_alloc()); *buf = 0; } ``` --- cfg/boost.cfg | 7 +++++++ lib/astutils.cpp | 16 ++++++++++------ test/cfg/boost.cpp | 14 ++++++++++++++ 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/cfg/boost.cfg b/cfg/boost.cfg index 87f7493df..40ec3a4a3 100644 --- a/cfg/boost.cfg +++ b/cfg/boost.cfg @@ -17,6 +17,7 @@ + @@ -968,4 +969,10 @@ + + true + + + + diff --git a/lib/astutils.cpp b/lib/astutils.cpp index bff663e01..c0ab6c08f 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -1066,16 +1066,20 @@ bool isUniqueExpression(const Token* tok) return isUniqueExpression(tok->astOperand2()); } -static bool isEscaped(const Token* tok, bool functionsScope) +static bool isEscaped(const Token* tok, bool functionsScope, const Library* library) { + if (library && library->isnoreturn(tok)) + return true; if (functionsScope) return Token::simpleMatch(tok, "throw"); else return Token::Match(tok, "return|throw"); } -static bool isEscapedOrJump(const Token* tok, bool functionsScope) +static bool isEscapedOrJump(const Token* tok, bool functionsScope, const Library* library) { + if (library && library->isnoreturn(tok)) + return true; if (functionsScope) return Token::simpleMatch(tok, "throw"); else @@ -1148,7 +1152,7 @@ bool isReturnScope(const Token* const endToken, const Library* library, const To !Token::findsimplematch(prev->link(), "break", prev)) { return true; } - if (isEscaped(prev->link()->astTop(), functionScope)) + if (isEscaped(prev->link()->astTop(), functionScope, library)) return true; if (Token::Match(prev->link()->previous(), "[;{}] {")) return isReturnScope(prev, library, unknownFunc, functionScope); @@ -1162,13 +1166,13 @@ bool isReturnScope(const Token* const endToken, const Library* library, const To return false; } if (Token::simpleMatch(prev->previous(), ") ;") && prev->previous()->link() && - isEscaped(prev->previous()->link()->astTop(), functionScope)) + isEscaped(prev->previous()->link()->astTop(), functionScope, library)) return true; - if (isEscaped(prev->previous()->astTop(), functionScope)) + if (isEscaped(prev->previous()->astTop(), functionScope, library)) return true; // return/goto statement prev = prev->previous(); - while (prev && !Token::Match(prev, ";|{|}") && !isEscapedOrJump(prev, functionScope)) + while (prev && !Token::Match(prev, ";|{|}") && !isEscapedOrJump(prev, functionScope, library)) prev = prev->previous(); return prev && prev->isName(); } diff --git a/test/cfg/boost.cpp b/test/cfg/boost.cpp index a83f7e604..0ef74ac71 100644 --- a/test/cfg/boost.cpp +++ b/test/cfg/boost.cpp @@ -67,3 +67,17 @@ void uninitvar() // cppcheck-suppress uninitvar (void)boost::math::round(intUninit2); } + +void throwexception(int * buf) +{ + if (!buf) + boost::throw_exception(std::bad_alloc()); + *buf = 0; +} + +void throwexception2(int * buf) +{ + if (!buf) + BOOST_THROW_EXCEPTION(std::bad_alloc()); + *buf = 0; +}