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:
parent
3e0d1141d3
commit
ee7fe3aaa1
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue