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; } ```
This commit is contained in:
parent
fe4657f218
commit
c297ed8204
|
@ -17,6 +17,7 @@
|
|||
<define name="BOOST_FORCEINLINE" value="inline"/>
|
||||
<define name="BOOST_NOINLINE" value=""/>
|
||||
<define name="BOOST_NORETURN" value="[[noreturn]]"/>
|
||||
<define name="BOOST_THROW_EXCEPTION(X)" value="boost::throw_exception(X)"/>
|
||||
<define name="BOOST_LIKELY(X)" value="(X)"/>
|
||||
<define name="BOOST_UNLIKELY(X)" value="(X)"/>
|
||||
<define name="BOOST_FIXTURE_TEST_SUITE(...)" value=""/>
|
||||
|
@ -968,4 +969,10 @@
|
|||
<not-bool/>
|
||||
</arg>
|
||||
</function>
|
||||
<function name="boost::throw_exception">
|
||||
<noreturn>true</noreturn>
|
||||
<arg nr="1" direction="in">
|
||||
<not-uninit/>
|
||||
</arg>
|
||||
</function>
|
||||
</def>
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue