Fix FP: Unitialized variable when using a pointer

This fixes the FP in cases like this:

```cpp
void f() {
    bool b;
    bool * x = &b;
    if (x != nullptr)
        x = 1;
}
```

It tracks the indirection of the uninit value in valueflow.
This commit is contained in:
Paul Fultz II 2019-08-17 07:36:41 +02:00 committed by Daniel Marjamäki
parent 3e0d1141d3
commit ee7fe3aaa1
5 changed files with 42 additions and 6 deletions

View File

@ -1308,6 +1308,11 @@ void CheckUninitVar::valueFlowUninit()
continue;
if (!isVariableUsage(tok, tok->variable()->isPointer(), tok->variable()->isArray() ? ARRAY : NO_ALLOC))
continue;
if (v->indirect > 1 || v->indirect < 0)
continue;
bool unknown;
if (v->indirect == 1 && !CheckNullPointer::isPointerDeRef(tok, unknown, mSettings))
continue;
if (!Token::Match(tok->astParent(), ". %name% (") && isVariableChanged(tok, mSettings, mTokenizer->isCPP()))
continue;
uninitvarError(tok, tok->str(), v->errorPath);

View File

@ -456,10 +456,18 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value, const Setti
}
if (value.isUninitValue()) {
if (parent->isUnaryOp("&"))
setTokenValue(parent, value, settings);
else if (Token::Match(parent, ". %var%") && parent->astOperand1() == tok)
setTokenValue(parent->astOperand2(), value, settings);
ValueFlow::Value pvalue = value;
if (parent->isUnaryOp("&")) {
pvalue.indirect++;
setTokenValue(parent, pvalue, settings);
} else if (Token::Match(parent, ". %var%") && parent->astOperand1() == tok) {
if (parent->originalName() == "->")
pvalue.indirect--;
setTokenValue(parent->astOperand2(), pvalue, settings);
} else if (parent->isUnaryOp("*") && pvalue.indirect > 0) {
pvalue.indirect--;
setTokenValue(parent, pvalue, settings);
}
return;
}
@ -5713,6 +5721,7 @@ ValueFlow::Value::Value(const Token *c, long long val)
safe(false),
conditional(false),
defaultArg(false),
indirect(0),
lifetimeKind(LifetimeKind::Object),
lifetimeScope(LifetimeScope::Local),
valueKind(ValueKind::Possible)

View File

@ -53,6 +53,7 @@ namespace ValueFlow {
safe(false),
conditional(false),
defaultArg(false),
indirect(0),
lifetimeKind(LifetimeKind::Object),
lifetimeScope(LifetimeScope::Local),
valueKind(ValueKind::Possible)
@ -100,6 +101,7 @@ namespace ValueFlow {
varId == rhs.varId &&
conditional == rhs.conditional &&
defaultArg == rhs.defaultArg &&
indirect == rhs.indirect &&
valueKind == rhs.valueKind;
}
@ -175,6 +177,8 @@ namespace ValueFlow {
/** Is this value passed as default parameter to the function? */
bool defaultArg;
int indirect;
enum class LifetimeKind {Object, Lambda, Iterator, Address} lifetimeKind;
enum class LifetimeScope { Local, Argument } lifetimeScope;

View File

@ -3197,7 +3197,7 @@ private:
" }\n"
"}\n");
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:5]: (style) Condition 'array' is always true\n", errout.str());
check("void f(int *array, int size ) {\n"
" for(int i = 0; i < size; ++i) {\n"
" if(array == 0)\n"
@ -3206,7 +3206,7 @@ private:
" }\n"
"}\n");
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:5]: (style) Condition 'array' is always true\n", errout.str());
// #9277
check("int f() {\n"
" constexpr bool x = true;\n"

View File

@ -4013,6 +4013,24 @@ private:
"}\n");
ASSERT_EQUALS("", errout.str());
valueFlowUninit("void f(bool * x) {\n"
" if (x != nullptr)\n"
" x = 1;\n"
"}\n"
"void g() {\n"
" bool x;\n"
" f(&x);\n"
"}\n");
ASSERT_EQUALS("", errout.str());
valueFlowUninit("void f() {\n"
" bool b;\n"
" bool * x = &b;\n"
" if (x != nullptr)\n"
" x = 1;\n"
"}\n");
ASSERT_EQUALS("", errout.str());
valueFlowUninit("struct A { bool b; };"
"void f(A * x) {\n"
" x->b = false;\n"