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:
Ken-Patrick Lehrmann 2020-06-17 19:01:32 +02:00
parent fe4657f218
commit c297ed8204
3 changed files with 31 additions and 6 deletions

View File

@ -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>

View File

@ -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();
}

View File

@ -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;
}