Fix issue 6010: Uninitialized inner struct (#2098)
* Fix issue 6010: Uninitialized inner struct * Show to root variable that is unitialized * Warn on pointer dereferences
This commit is contained in:
parent
5bbc7ee6b6
commit
c0a8d628b9
@ -52,6 +52,26 @@ void visitAstNodes(const Token *ast, std::function<ChildrenToVisit(const Token *
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void astFlattenRecursive(const Token *tok, std::vector<const Token *> *result, const char* op, nonneg int depth = 0)
|
||||||
|
{
|
||||||
|
++depth;
|
||||||
|
if (!tok || depth >= 100)
|
||||||
|
return;
|
||||||
|
if (tok->str() == op) {
|
||||||
|
astFlattenRecursive(tok->astOperand1(), result, op, depth);
|
||||||
|
astFlattenRecursive(tok->astOperand2(), result, op, depth);
|
||||||
|
} else {
|
||||||
|
result->push_back(tok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<const Token*> astFlatten(const Token* tok, const char* op)
|
||||||
|
{
|
||||||
|
std::vector<const Token*> result;
|
||||||
|
astFlattenRecursive(tok, &result, op);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool astIsCharWithSign(const Token *tok, ValueType::Sign sign)
|
static bool astIsCharWithSign(const Token *tok, ValueType::Sign sign)
|
||||||
{
|
{
|
||||||
|
@ -48,6 +48,8 @@ enum class ChildrenToVisit {
|
|||||||
*/
|
*/
|
||||||
void visitAstNodes(const Token *ast, std::function<ChildrenToVisit(const Token *)> visitor);
|
void visitAstNodes(const Token *ast, std::function<ChildrenToVisit(const Token *)> visitor);
|
||||||
|
|
||||||
|
std::vector<const Token*> astFlatten(const Token* tok, const char* op);
|
||||||
|
|
||||||
/** Is expression a 'signed char' if no promotion is used */
|
/** Is expression a 'signed char' if no promotion is used */
|
||||||
bool astIsSignedChar(const Token *tok);
|
bool astIsSignedChar(const Token *tok);
|
||||||
/** Is expression a 'char' if no promotion is used? */
|
/** Is expression a 'char' if no promotion is used? */
|
||||||
|
@ -1284,6 +1284,18 @@ void CheckUninitVar::uninitStructMemberError(const Token *tok, const std::string
|
|||||||
"$symbol:" + membername + "\nUninitialized struct member: $symbol", CWE908, false);
|
"$symbol:" + membername + "\nUninitialized struct member: $symbol", CWE908, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isLeafDot(const Token* tok)
|
||||||
|
{
|
||||||
|
if (!tok)
|
||||||
|
return false;
|
||||||
|
const Token * parent = tok->astParent();
|
||||||
|
if (!Token::simpleMatch(parent, "."))
|
||||||
|
return false;
|
||||||
|
if (parent->astOperand2() == tok)
|
||||||
|
return true;
|
||||||
|
return isLeafDot(parent);
|
||||||
|
}
|
||||||
|
|
||||||
void CheckUninitVar::valueFlowUninit()
|
void CheckUninitVar::valueFlowUninit()
|
||||||
{
|
{
|
||||||
const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
|
const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
|
||||||
@ -1299,8 +1311,6 @@ void CheckUninitVar::valueFlowUninit()
|
|||||||
}
|
}
|
||||||
if (!tok->variable())
|
if (!tok->variable())
|
||||||
continue;
|
continue;
|
||||||
if (Token::Match(tok->astParent(), ". %var%") && tok->astParent()->astOperand1() == tok)
|
|
||||||
continue;
|
|
||||||
auto v = std::find_if(tok->values().begin(), tok->values().end(), std::mem_fn(&ValueFlow::Value::isUninitValue));
|
auto v = std::find_if(tok->values().begin(), tok->values().end(), std::mem_fn(&ValueFlow::Value::isUninitValue));
|
||||||
if (v == tok->values().end())
|
if (v == tok->values().end())
|
||||||
continue;
|
continue;
|
||||||
@ -1311,11 +1321,19 @@ void CheckUninitVar::valueFlowUninit()
|
|||||||
if (v->indirect > 1 || v->indirect < 0)
|
if (v->indirect > 1 || v->indirect < 0)
|
||||||
continue;
|
continue;
|
||||||
bool unknown;
|
bool unknown;
|
||||||
if (v->indirect == 1 && !CheckNullPointer::isPointerDeRef(tok, unknown, mSettings))
|
const bool deref = CheckNullPointer::isPointerDeRef(tok, unknown, mSettings);
|
||||||
|
if (v->indirect == 1 && !deref)
|
||||||
|
continue;
|
||||||
|
if (Token::Match(tok->astParent(), ". %var%") && !(isLeafDot(tok) || deref))
|
||||||
continue;
|
continue;
|
||||||
if (!Token::Match(tok->astParent(), ". %name% (") && isVariableChanged(tok, mSettings, mTokenizer->isCPP()))
|
if (!Token::Match(tok->astParent(), ". %name% (") && isVariableChanged(tok, mSettings, mTokenizer->isCPP()))
|
||||||
continue;
|
continue;
|
||||||
uninitvarError(tok, tok->str(), v->errorPath);
|
uninitvarError(tok, tok->str(), v->errorPath);
|
||||||
|
const Token * nextTok = tok;
|
||||||
|
while(Token::simpleMatch(nextTok->astParent(), "."))
|
||||||
|
nextTok = nextTok->astParent();
|
||||||
|
nextTok = nextAfterAstRightmostLeaf(nextTok);
|
||||||
|
tok = nextTok ? nextTok : tok;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -461,9 +461,13 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value, const Setti
|
|||||||
pvalue.indirect++;
|
pvalue.indirect++;
|
||||||
setTokenValue(parent, pvalue, settings);
|
setTokenValue(parent, pvalue, settings);
|
||||||
} else if (Token::Match(parent, ". %var%") && parent->astOperand1() == tok) {
|
} else if (Token::Match(parent, ". %var%") && parent->astOperand1() == tok) {
|
||||||
if (parent->originalName() == "->")
|
if (parent->originalName() == "->" && pvalue.indirect > 0)
|
||||||
pvalue.indirect--;
|
pvalue.indirect--;
|
||||||
setTokenValue(parent->astOperand2(), pvalue, settings);
|
setTokenValue(parent->astOperand2(), pvalue, settings);
|
||||||
|
} else if (Token::Match(parent->astParent(), ". %var%") && parent->astParent()->astOperand1() == parent) {
|
||||||
|
if (parent->astParent()->originalName() == "->" && pvalue.indirect > 0)
|
||||||
|
pvalue.indirect--;
|
||||||
|
setTokenValue(parent->astParent()->astOperand2(), pvalue, settings);
|
||||||
} else if (parent->isUnaryOp("*") && pvalue.indirect > 0) {
|
} else if (parent->isUnaryOp("*") && pvalue.indirect > 0) {
|
||||||
pvalue.indirect--;
|
pvalue.indirect--;
|
||||||
setTokenValue(parent, pvalue, settings);
|
setTokenValue(parent, pvalue, settings);
|
||||||
|
@ -4004,6 +4004,17 @@ private:
|
|||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("[test.cpp:7]: (error) Uninitialized variable: flags\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:7]: (error) Uninitialized variable: flags\n", errout.str());
|
||||||
|
|
||||||
|
valueFlowUninit("struct pc_data {\n"
|
||||||
|
" struct {\n"
|
||||||
|
" char * strefa;\n"
|
||||||
|
" } wampiryzm;\n"
|
||||||
|
"};\n"
|
||||||
|
"void f() {\n"
|
||||||
|
" struct pc_data *pcdata;\n"
|
||||||
|
" if ( *pcdata->wampiryzm.strefa == '\\0' ) { }\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:8]: (error) Uninitialized variable: pcdata\n", errout.str());
|
||||||
|
|
||||||
valueFlowUninit("void f(bool * x) {\n"
|
valueFlowUninit("void f(bool * x) {\n"
|
||||||
" *x = false;\n"
|
" *x = false;\n"
|
||||||
"}\n"
|
"}\n"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user