Multipass Valueflow
This commit is contained in:
parent
6138294e3d
commit
ef35b86b4a
|
@ -100,6 +100,8 @@
|
||||||
#include <stack>
|
#include <stack>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
static const int TIMEOUT = 10; // Do not repeat ValueFlow analysis more than 10 seconds
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
struct ProgramMemory {
|
struct ProgramMemory {
|
||||||
std::map<unsigned int, ValueFlow::Value> values;
|
std::map<unsigned int, ValueFlow::Value> values;
|
||||||
|
@ -2404,7 +2406,7 @@ static void valueFlowAfterAssign(TokenList *tokenlist, SymbolDatabase* symboldat
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Lhs should be a variable
|
// Lhs should be a variable
|
||||||
if (!tok->astOperand1() || !tok->astOperand1()->varId())
|
if (!tok->astOperand1() || !tok->astOperand1()->varId() || tok->astOperand1()->hasKnownValue())
|
||||||
continue;
|
continue;
|
||||||
const unsigned int varid = tok->astOperand1()->varId();
|
const unsigned int varid = tok->astOperand1()->varId();
|
||||||
if (aliased.find(varid) != aliased.end())
|
if (aliased.find(varid) != aliased.end())
|
||||||
|
@ -3367,6 +3369,9 @@ static void valueFlowFunctionReturn(TokenList *tokenlist, ErrorLogger *errorLogg
|
||||||
if (tok->str() != "(" || !tok->astOperand1() || !tok->astOperand1()->function())
|
if (tok->str() != "(" || !tok->astOperand1() || !tok->astOperand1()->function())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (tok->hasKnownValue())
|
||||||
|
continue;
|
||||||
|
|
||||||
// Arguments..
|
// Arguments..
|
||||||
std::vector<MathLib::bigint> parvalues;
|
std::vector<MathLib::bigint> parvalues;
|
||||||
if (tok->astOperand2()) {
|
if (tok->astOperand2()) {
|
||||||
|
@ -3623,6 +3628,8 @@ static void valueFlowContainerSize(TokenList *tokenlist, SymbolDatabase* symbold
|
||||||
continue;
|
continue;
|
||||||
if (!Token::Match(var->nameToken(), "%name% ;"))
|
if (!Token::Match(var->nameToken(), "%name% ;"))
|
||||||
continue;
|
continue;
|
||||||
|
if (var->nameToken()->hasKnownValue())
|
||||||
|
continue;
|
||||||
ValueFlow::Value value(0);
|
ValueFlow::Value value(0);
|
||||||
if (var->valueType()->container->size_templateArgNo >= 0) {
|
if (var->valueType()->container->size_templateArgNo >= 0) {
|
||||||
if (var->dimensions().size() == 1 && var->dimensions().front().known)
|
if (var->dimensions().size() == 1 && var->dimensions().front().known)
|
||||||
|
@ -3760,6 +3767,13 @@ const ValueFlow::Value *ValueFlow::valueFlowConstantFoldAST(const Token *expr, c
|
||||||
return expr && expr->hasKnownValue() ? &expr->values().front() : nullptr;
|
return expr && expr->hasKnownValue() ? &expr->values().front() : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::size_t getTotalValues(TokenList *tokenlist)
|
||||||
|
{
|
||||||
|
std::size_t n = 1;
|
||||||
|
for (Token *tok = tokenlist->front(); tok; tok = tok->next())
|
||||||
|
n += tok->values().size();
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings)
|
void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings)
|
||||||
{
|
{
|
||||||
|
@ -3773,6 +3787,12 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase,
|
||||||
valueFlowPointerAlias(tokenlist);
|
valueFlowPointerAlias(tokenlist);
|
||||||
valueFlowFunctionReturn(tokenlist, errorLogger);
|
valueFlowFunctionReturn(tokenlist, errorLogger);
|
||||||
valueFlowBitAnd(tokenlist);
|
valueFlowBitAnd(tokenlist);
|
||||||
|
|
||||||
|
// Temporary hack.. run valueflow until there is nothing to update or timeout expires
|
||||||
|
const std::time_t timeout = std::time(0) + TIMEOUT;
|
||||||
|
std::size_t values = 0;
|
||||||
|
while (std::time(0) < timeout && values < getTotalValues(tokenlist)) {
|
||||||
|
values = getTotalValues(tokenlist);
|
||||||
valueFlowOppositeCondition(symboldatabase, settings);
|
valueFlowOppositeCondition(symboldatabase, settings);
|
||||||
valueFlowBeforeCondition(tokenlist, symboldatabase, errorLogger, settings);
|
valueFlowBeforeCondition(tokenlist, symboldatabase, errorLogger, settings);
|
||||||
valueFlowAfterMove(tokenlist, symboldatabase, errorLogger, settings);
|
valueFlowAfterMove(tokenlist, symboldatabase, errorLogger, settings);
|
||||||
|
@ -3786,6 +3806,7 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase,
|
||||||
if (tokenlist->isCPP())
|
if (tokenlist->isCPP())
|
||||||
valueFlowContainerSize(tokenlist, symboldatabase, errorLogger, settings);
|
valueFlowContainerSize(tokenlist, symboldatabase, errorLogger, settings);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string ValueFlow::eitherTheConditionIsRedundant(const Token *condition)
|
std::string ValueFlow::eitherTheConditionIsRedundant(const Token *condition)
|
||||||
|
|
|
@ -82,6 +82,7 @@ private:
|
||||||
TEST_CASE(nullpointer28); // #6491
|
TEST_CASE(nullpointer28); // #6491
|
||||||
TEST_CASE(nullpointer30); // #6392
|
TEST_CASE(nullpointer30); // #6392
|
||||||
TEST_CASE(nullpointer31); // #8482
|
TEST_CASE(nullpointer31); // #8482
|
||||||
|
TEST_CASE(nullpointer32); // #8460
|
||||||
TEST_CASE(nullpointer_addressOf); // address of
|
TEST_CASE(nullpointer_addressOf); // address of
|
||||||
TEST_CASE(nullpointerSwitch); // #2626
|
TEST_CASE(nullpointerSwitch); // #2626
|
||||||
TEST_CASE(nullpointer_cast); // #4692
|
TEST_CASE(nullpointer_cast); // #4692
|
||||||
|
@ -1376,6 +1377,18 @@ private:
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nullpointer32() { // #8460
|
||||||
|
check("int f(int * ptr) {\n"
|
||||||
|
" if(ptr)\n"
|
||||||
|
" { return 0;}\n"
|
||||||
|
" else{\n"
|
||||||
|
" int *p1 = ptr;\n"
|
||||||
|
" return *p1;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n", true);
|
||||||
|
ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:6]: (warning) Either the condition 'ptr' is redundant or there is possible null pointer dereference: p1.\n", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
void nullpointer_addressOf() { // address of
|
void nullpointer_addressOf() { // address of
|
||||||
check("void f() {\n"
|
check("void f() {\n"
|
||||||
" struct X *x = 0;\n"
|
" struct X *x = 0;\n"
|
||||||
|
|
Loading…
Reference in New Issue