Fix issue 9496: False negative: Dereferencing returned smart null-pointer

This commit is contained in:
Paul 2020-09-08 21:54:38 -05:00
parent 5376decbe7
commit 382408f59e
5 changed files with 65 additions and 37 deletions

View File

@ -21,6 +21,7 @@
#include "astutils.h" #include "astutils.h"
#include "errorlogger.h" #include "errorlogger.h"
#include "library.h"
#include "mathlib.h" #include "mathlib.h"
#include "platform.h" #include "platform.h"
#include "settings.h" #include "settings.h"
@ -5968,7 +5969,8 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to
valuetype.sign = ValueType::Sign::SIGNED; valuetype.sign = ValueType::Sign::SIGNED;
} }
setValueType(tok, valuetype); setValueType(tok, valuetype);
} else if (tok->link() && tok->str() == "(") { } else if (tok->link() && Token::Match(tok, "(|{")) {
const Token* start = tok->astOperand1() ? tok->astOperand1()->findExpressionStartEndTokens().first : nullptr;
// cast // cast
if (tok->isCast() && !tok->astOperand2() && Token::Match(tok, "( %name%")) { if (tok->isCast() && !tok->astOperand2() && Token::Match(tok, "( %name%")) {
ValueType valuetype; ValueType valuetype;
@ -5983,6 +5985,16 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to
setValueType(tok, valuetype); setValueType(tok, valuetype);
} }
// Construct smart pointer
else if (mSettings->library.isSmartPointer(start)) {
ValueType valuetype;
if (parsedecl(start, &valuetype, mDefaultSignedness, mSettings)) {
setValueType(tok, valuetype);
setValueType(tok->astOperand1(), valuetype);
}
}
// function // function
else if (tok->previous() && tok->previous()->function() && tok->previous()->function()->retDef) { else if (tok->previous() && tok->previous()->function() && tok->previous()->function()->retDef) {
ValueType valuetype; ValueType valuetype;

View File

@ -5952,8 +5952,7 @@ static void valueFlowSmartPointer(TokenList *tokenlist, ErrorLogger * errorLogge
continue; continue;
if (!tok->scope()->isExecutable()) if (!tok->scope()->isExecutable())
continue; continue;
if (!tok->variable()) if (tok->variable()) {
continue;
const Variable * var = tok->variable(); const Variable * var = tok->variable();
if (!var->isSmartPointer()) if (!var->isSmartPointer())
continue; continue;
@ -5994,6 +5993,13 @@ static void valueFlowSmartPointer(TokenList *tokenlist, ErrorLogger * errorLogge
values.push_back(v); values.push_back(v);
valueFlowForwardAssign(tok->tokAt(4), var, values, false, false, tokenlist, errorLogger, settings); valueFlowForwardAssign(tok->tokAt(4), var, values, false, false, tokenlist, errorLogger, settings);
} }
} else if (Token::Match(tok->previous(), "%name%|> (|{") && astIsSmartPointer(tok) && astIsSmartPointer(tok->astOperand1())) {
std::vector<const Token*> args = getArguments(tok);
if (args.empty())
continue;
for(const ValueFlow::Value& v:args.front()->values())
setTokenValue(tok, v, settings);
}
} }
} }
@ -6681,7 +6687,6 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase,
valueFlowGlobalStaticVar(tokenlist, settings); valueFlowGlobalStaticVar(tokenlist, settings);
valueFlowPointerAlias(tokenlist); valueFlowPointerAlias(tokenlist);
valueFlowLifetime(tokenlist, symboldatabase, errorLogger, settings); valueFlowLifetime(tokenlist, symboldatabase, errorLogger, settings);
valueFlowFunctionReturn(tokenlist, errorLogger);
valueFlowBitAnd(tokenlist); valueFlowBitAnd(tokenlist);
valueFlowSameExpressions(tokenlist); valueFlowSameExpressions(tokenlist);
valueFlowFwdAnalysis(tokenlist, settings); valueFlowFwdAnalysis(tokenlist, settings);
@ -6703,6 +6708,7 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase,
valueFlowSwitchVariable(tokenlist, symboldatabase, errorLogger, settings); valueFlowSwitchVariable(tokenlist, symboldatabase, errorLogger, settings);
valueFlowForLoop(tokenlist, symboldatabase, errorLogger, settings); valueFlowForLoop(tokenlist, symboldatabase, errorLogger, settings);
valueFlowSubFunction(tokenlist, symboldatabase, errorLogger, settings); valueFlowSubFunction(tokenlist, symboldatabase, errorLogger, settings);
valueFlowFunctionReturn(tokenlist, errorLogger);
valueFlowFunctionDefaultParameter(tokenlist, symboldatabase, errorLogger, settings); valueFlowFunctionDefaultParameter(tokenlist, symboldatabase, errorLogger, settings);
valueFlowUninit(tokenlist, symboldatabase, errorLogger, settings); valueFlowUninit(tokenlist, symboldatabase, errorLogger, settings);
if (tokenlist->isCPP()) { if (tokenlist->isCPP()) {

View File

@ -1442,7 +1442,7 @@ private:
check("auto& f() {\n" check("auto& f() {\n"
" return std::vector<int>{1}.front();\n" " return std::vector<int>{1}.front();\n"
"}\n"); "}\n");
TODO_ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:3]: (error) Reference to temporary returned.\n", "", errout.str()); ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:2]: (error) Reference to temporary returned.\n", errout.str());
check("struct A { int foo; };\n" check("struct A { int foo; };\n"
"int& f(std::vector<A> v) {\n" "int& f(std::vector<A> v) {\n"

View File

@ -2859,6 +2859,15 @@ private:
" return x.release();\n" " return x.release();\n"
"}\n", true); "}\n", true);
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
// #9496
check("std::shared_ptr<int> f() {\n"
" return std::shared_ptr<int>(nullptr);\n"
"}\n"
"void g() {\n"
" int a = *f();\n"
"}\n", true);
ASSERT_EQUALS("[test.cpp:5]: (error) Null pointer dereference: f()\n", errout.str());
} }
void functioncall() { // #3443 - function calls void functioncall() { // #3443 - function calls

View File

@ -1152,6 +1152,7 @@ private:
ASSERT_EQUALS(expected, tok(code, false)); ASSERT_EQUALS(expected, tok(code, false));
ASSERT_EQUALS_WITHOUT_LINENUMBERS( ASSERT_EQUALS_WITHOUT_LINENUMBERS(
"[test.cpp:31]: (debug) valueflow.cpp:3109:valueFlowFunctionReturn bailout: function return; nontrivial function body\n"
"[test.cpp:28]: (debug) valueflow.cpp:3109:valueFlowFunctionReturn bailout: function return; nontrivial function body\n" "[test.cpp:28]: (debug) valueflow.cpp:3109:valueFlowFunctionReturn bailout: function return; nontrivial function body\n"
, errout.str()); , errout.str());
} }