Fix 10538: FN: nullPointer (std::swap pointers) (#3504)
This commit is contained in:
parent
130d1abbce
commit
89515600e4
|
@ -144,7 +144,8 @@ static int getArgumentPos(const Token* ftok, const Token* tokToFind){
|
||||||
return findArgumentPos(startTok, tokToFind);
|
return findArgumentPos(startTok, tokToFind);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void astFlattenRecursive(const Token *tok, std::vector<const Token *> *result, const char* op, nonneg int depth = 0)
|
template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
|
||||||
|
static void astFlattenRecursive(T* tok, std::vector<T*>* result, const char* op, nonneg int depth = 0)
|
||||||
{
|
{
|
||||||
++depth;
|
++depth;
|
||||||
if (!tok || depth >= 100)
|
if (!tok || depth >= 100)
|
||||||
|
@ -164,6 +165,12 @@ std::vector<const Token*> astFlatten(const Token* tok, const char* op)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<Token*> astFlatten(Token* tok, const char* op)
|
||||||
|
{
|
||||||
|
std::vector<Token*> result;
|
||||||
|
astFlattenRecursive(tok, &result, op);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
bool astHasToken(const Token* root, const Token * tok)
|
bool astHasToken(const Token* root, const Token * tok)
|
||||||
{
|
{
|
||||||
|
|
|
@ -58,6 +58,7 @@ const Token* findExpression(const nonneg int exprid,
|
||||||
const Token* findExpression(const Token* start, const nonneg int exprid);
|
const Token* findExpression(const Token* start, const nonneg int exprid);
|
||||||
|
|
||||||
std::vector<const Token*> astFlatten(const Token* tok, const char* op);
|
std::vector<const Token*> astFlatten(const Token* tok, const char* op);
|
||||||
|
std::vector<Token*> astFlatten(Token* tok, const char* op);
|
||||||
|
|
||||||
bool astHasToken(const Token* root, const Token * tok);
|
bool astHasToken(const Token* root, const Token * tok);
|
||||||
|
|
||||||
|
|
|
@ -4805,6 +4805,41 @@ static void valueFlowAfterAssign(TokenList *tokenlist, SymbolDatabase* symboldat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::vector<const Variable*> getVariables(const Token* tok)
|
||||||
|
{
|
||||||
|
std::vector<const Variable*> result;
|
||||||
|
visitAstNodes(tok, [&](const Token* child) {
|
||||||
|
if (child->variable())
|
||||||
|
result.push_back(child->variable());
|
||||||
|
return ChildrenToVisit::op1_and_op2;
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void valueFlowAfterSwap(TokenList* tokenlist,
|
||||||
|
SymbolDatabase* symboldatabase,
|
||||||
|
ErrorLogger* errorLogger,
|
||||||
|
const Settings* settings)
|
||||||
|
{
|
||||||
|
for (const Scope* scope : symboldatabase->functionScopes) {
|
||||||
|
for (Token* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
|
||||||
|
if (!Token::simpleMatch(tok, "swap ("))
|
||||||
|
continue;
|
||||||
|
if (!Token::simpleMatch(tok->next()->astOperand2(), ","))
|
||||||
|
continue;
|
||||||
|
std::vector<Token*> args = astFlatten(tok->next()->astOperand2(), ",");
|
||||||
|
if (args.size() != 2)
|
||||||
|
continue;
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
std::vector<const Variable*> vars = getVariables(args[0]);
|
||||||
|
std::list<ValueFlow::Value> values = args[0]->values();
|
||||||
|
valueFlowForwardAssign(args[0], args[1], vars, values, false, tokenlist, errorLogger, settings);
|
||||||
|
std::swap(args[0], args[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void valueFlowSetConditionToKnown(const Token* tok, std::list<ValueFlow::Value>& values, bool then)
|
static void valueFlowSetConditionToKnown(const Token* tok, std::list<ValueFlow::Value>& values, bool then)
|
||||||
{
|
{
|
||||||
if (values.empty())
|
if (values.empty())
|
||||||
|
@ -6559,17 +6594,6 @@ static bool isContainerSizeChanged(nonneg int varId,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<const Variable*> getVariables(const Token* tok)
|
|
||||||
{
|
|
||||||
std::vector<const Variable*> result;
|
|
||||||
visitAstNodes(tok, [&](const Token* child) {
|
|
||||||
if (child->variable())
|
|
||||||
result.push_back(child->variable());
|
|
||||||
return ChildrenToVisit::op1_and_op2;
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void valueFlowSmartPointer(TokenList *tokenlist, ErrorLogger * errorLogger, const Settings *settings)
|
static void valueFlowSmartPointer(TokenList *tokenlist, ErrorLogger * errorLogger, const Settings *settings)
|
||||||
{
|
{
|
||||||
for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
|
for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
|
||||||
|
@ -7419,6 +7443,7 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase,
|
||||||
valueFlowArrayBool(tokenlist);
|
valueFlowArrayBool(tokenlist);
|
||||||
valueFlowRightShift(tokenlist, settings);
|
valueFlowRightShift(tokenlist, settings);
|
||||||
valueFlowAfterAssign(tokenlist, symboldatabase, errorLogger, settings);
|
valueFlowAfterAssign(tokenlist, symboldatabase, errorLogger, settings);
|
||||||
|
valueFlowAfterSwap(tokenlist, symboldatabase, errorLogger, settings);
|
||||||
valueFlowCondition(SimpleConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings);
|
valueFlowCondition(SimpleConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings);
|
||||||
valueFlowInferCondition(tokenlist, settings);
|
valueFlowInferCondition(tokenlist, settings);
|
||||||
valueFlowSwitchVariable(tokenlist, symboldatabase, errorLogger, settings);
|
valueFlowSwitchVariable(tokenlist, symboldatabase, errorLogger, settings);
|
||||||
|
|
|
@ -83,6 +83,7 @@ private:
|
||||||
TEST_CASE(valueFlowBeforeConditionForward);
|
TEST_CASE(valueFlowBeforeConditionForward);
|
||||||
|
|
||||||
TEST_CASE(valueFlowAfterAssign);
|
TEST_CASE(valueFlowAfterAssign);
|
||||||
|
TEST_CASE(valueFlowAfterSwap);
|
||||||
TEST_CASE(valueFlowAfterCondition);
|
TEST_CASE(valueFlowAfterCondition);
|
||||||
TEST_CASE(valueFlowAfterConditionExpr);
|
TEST_CASE(valueFlowAfterConditionExpr);
|
||||||
TEST_CASE(valueFlowAfterConditionSeveralNot);
|
TEST_CASE(valueFlowAfterConditionSeveralNot);
|
||||||
|
@ -2465,6 +2466,31 @@ private:
|
||||||
ASSERT_EQUALS(false, testValueOfXImpossible(code, 3U, 1));
|
ASSERT_EQUALS(false, testValueOfXImpossible(code, 3U, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void valueFlowAfterSwap()
|
||||||
|
{
|
||||||
|
const char* code;
|
||||||
|
|
||||||
|
code = "int f() {\n"
|
||||||
|
" int a = 1;\n"
|
||||||
|
" int b = 2;\n"
|
||||||
|
" std::swap(a, b);\n"
|
||||||
|
" int x = a;\n"
|
||||||
|
" return x;\n"
|
||||||
|
"}";
|
||||||
|
ASSERT_EQUALS(true, testValueOfXKnown(code, 6U, 2));
|
||||||
|
ASSERT_EQUALS(false, testValueOfXKnown(code, 6U, 1));
|
||||||
|
|
||||||
|
code = "int f() {\n"
|
||||||
|
" int a = 1;\n"
|
||||||
|
" int b = 2;\n"
|
||||||
|
" std::swap(a, b);\n"
|
||||||
|
" int x = b;\n"
|
||||||
|
" return x;\n"
|
||||||
|
"}";
|
||||||
|
ASSERT_EQUALS(true, testValueOfXKnown(code, 6U, 1));
|
||||||
|
ASSERT_EQUALS(false, testValueOfXKnown(code, 6U, 2));
|
||||||
|
}
|
||||||
|
|
||||||
void valueFlowAfterCondition() {
|
void valueFlowAfterCondition() {
|
||||||
const char *code;
|
const char *code;
|
||||||
// in if
|
// in if
|
||||||
|
|
Loading…
Reference in New Issue