Fix #6475 FN uninitialized variable usage not detected (#3700)

This commit is contained in:
chrchr-github 2022-01-17 20:35:30 +01:00 committed by GitHub
parent 2148b8b165
commit 9c56e7ea8d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 45 additions and 16 deletions

View File

@ -306,13 +306,14 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer *tokenizer)
for (const Scope &scope : symbolDatabase->scopeList) { for (const Scope &scope : symbolDatabase->scopeList) {
if (!scope.isExecutable() || scope.type != Scope::eFunction || !scope.function) if (!scope.isExecutable() || scope.type != Scope::eFunction || !scope.function)
continue; continue;
const Function *const function = scope.function; const Function *const scopeFunction = scope.function;
// source function calls // source function calls
for (const Token *tok = scope.bodyStart; tok != scope.bodyEnd; tok = tok->next()) { for (const Token *tok = scope.bodyStart; tok != scope.bodyEnd; tok = tok->next()) {
if (tok->str() != "(" || !tok->astOperand1() || !tok->astOperand2()) if (tok->str() != "(" || !tok->astOperand1() || !tok->astOperand2())
continue; continue;
if (!tok->astOperand1()->function()) const Function* tokFunction = tok->astOperand1()->function();
if (!tokFunction)
continue; continue;
const std::vector<const Token *> args(getArguments(tok->previous())); const std::vector<const Token *> args(getArguments(tok->previous()));
for (int argnr = 0; argnr < args.size(); ++argnr) { for (int argnr = 0; argnr < args.size(); ++argnr) {
@ -327,7 +328,7 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer *tokenizer)
continue; continue;
FileInfo::FunctionCall functionCall; FileInfo::FunctionCall functionCall;
functionCall.callValueType = value.valueType; functionCall.callValueType = value.valueType;
functionCall.callId = getFunctionId(tokenizer, tok->astOperand1()->function()); functionCall.callId = getFunctionId(tokenizer, tokFunction);
functionCall.callFunctionName = tok->astOperand1()->expressionString(); functionCall.callFunctionName = tok->astOperand1()->expressionString();
functionCall.location = FileInfo::Location(tokenizer,tok); functionCall.location = FileInfo::Location(tokenizer,tok);
functionCall.callArgNr = argnr + 1; functionCall.callArgNr = argnr + 1;
@ -348,7 +349,7 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer *tokenizer)
if (argtok->variable() && argtok->variable()->isArray() && argtok->variable()->dimensions().size()==1 && argtok->variable()->dimension(0)>1) { if (argtok->variable() && argtok->variable()->isArray() && argtok->variable()->dimensions().size()==1 && argtok->variable()->dimension(0)>1) {
FileInfo::FunctionCall functionCall; FileInfo::FunctionCall functionCall;
functionCall.callValueType = ValueFlow::Value::ValueType::BUFFER_SIZE; functionCall.callValueType = ValueFlow::Value::ValueType::BUFFER_SIZE;
functionCall.callId = getFunctionId(tokenizer, tok->astOperand1()->function()); functionCall.callId = getFunctionId(tokenizer, tokFunction);
functionCall.callFunctionName = tok->astOperand1()->expressionString(); functionCall.callFunctionName = tok->astOperand1()->expressionString();
functionCall.location = FileInfo::Location(tokenizer, tok); functionCall.location = FileInfo::Location(tokenizer, tok);
functionCall.callArgNr = argnr + 1; functionCall.callArgNr = argnr + 1;
@ -361,7 +362,7 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer *tokenizer)
if (argtok->isUnaryOp("&") && argtok->astOperand1()->variable() && argtok->astOperand1()->valueType() && !argtok->astOperand1()->variable()->isArray()) { if (argtok->isUnaryOp("&") && argtok->astOperand1()->variable() && argtok->astOperand1()->valueType() && !argtok->astOperand1()->variable()->isArray()) {
FileInfo::FunctionCall functionCall; FileInfo::FunctionCall functionCall;
functionCall.callValueType = ValueFlow::Value::ValueType::BUFFER_SIZE; functionCall.callValueType = ValueFlow::Value::ValueType::BUFFER_SIZE;
functionCall.callId = getFunctionId(tokenizer, tok->astOperand1()->function()); functionCall.callId = getFunctionId(tokenizer, tokFunction);
functionCall.callFunctionName = tok->astOperand1()->expressionString(); functionCall.callFunctionName = tok->astOperand1()->expressionString();
functionCall.location = FileInfo::Location(tokenizer, tok); functionCall.location = FileInfo::Location(tokenizer, tok);
functionCall.callArgNr = argnr + 1; functionCall.callArgNr = argnr + 1;
@ -370,19 +371,31 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer *tokenizer)
functionCall.warning = false; functionCall.warning = false;
fileInfo->functionCalls.push_back(functionCall); fileInfo->functionCalls.push_back(functionCall);
} }
// pointer to uninitialized data.. // pointer/reference to uninitialized data
auto isAddressOfArg = [](const Token* argtok) -> const Token* {
if (!argtok->isUnaryOp("&")) if (!argtok->isUnaryOp("&"))
continue; return nullptr;
argtok = argtok->astOperand1(); argtok = argtok->astOperand1();
if (!argtok || !argtok->valueType() || argtok->valueType()->pointer != 0) if (!argtok || !argtok->valueType() || argtok->valueType()->pointer != 0)
return nullptr;
return argtok;
};
auto isReferenceArg = [&](const Token* argtok) -> const Token* {
const Variable* argvar = tokFunction->getArgumentVar(argnr);
if (!argvar || !argvar->valueType() || argvar->valueType()->reference == Reference::None)
return nullptr;
return argtok;
};
const Token* addr = isAddressOfArg(argtok);
argtok = addr ? addr : isReferenceArg(argtok);
if (!argtok || argtok->values().size() != 1U)
continue; continue;
if (argtok->values().size() != 1U)
continue;
const ValueFlow::Value &v = argtok->values().front(); const ValueFlow::Value &v = argtok->values().front();
if (v.valueType == ValueFlow::Value::ValueType::UNINIT && !v.isInconclusive()) { if (v.valueType == ValueFlow::Value::ValueType::UNINIT && !v.isInconclusive()) {
FileInfo::FunctionCall functionCall; FileInfo::FunctionCall functionCall;
functionCall.callValueType = ValueFlow::Value::ValueType::UNINIT; functionCall.callValueType = ValueFlow::Value::ValueType::UNINIT;
functionCall.callId = getFunctionId(tokenizer, tok->astOperand1()->function()); functionCall.callId = getFunctionId(tokenizer, tokFunction);
functionCall.callFunctionName = tok->astOperand1()->expressionString(); functionCall.callFunctionName = tok->astOperand1()->expressionString();
functionCall.location = FileInfo::Location(tokenizer, tok); functionCall.location = FileInfo::Location(tokenizer, tok);
functionCall.callArgNr = argnr + 1; functionCall.callArgNr = argnr + 1;
@ -396,11 +409,11 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer *tokenizer)
} }
// Nested function calls // Nested function calls
for (int argnr = 0; argnr < function->argCount(); ++argnr) { for (int argnr = 0; argnr < scopeFunction->argCount(); ++argnr) {
const Token *tok; const Token *tok;
const int argnr2 = isCallFunction(&scope, argnr, &tok); const int argnr2 = isCallFunction(&scope, argnr, &tok);
if (argnr2 > 0) { if (argnr2 > 0) {
FileInfo::NestedCall nestedCall(tokenizer, function, tok); FileInfo::NestedCall nestedCall(tokenizer, scopeFunction, tok);
nestedCall.myArgNr = argnr + 1; nestedCall.myArgNr = argnr + 1;
nestedCall.callArgNr = argnr2; nestedCall.callArgNr = argnr2;
fileInfo->nestedCalls.push_back(nestedCall); fileInfo->nestedCalls.push_back(nestedCall);
@ -415,7 +428,7 @@ static std::list<std::pair<const Token *, MathLib::bigint>> getUnsafeFunction(co
{ {
std::list<std::pair<const Token *, MathLib::bigint>> ret; std::list<std::pair<const Token *, MathLib::bigint>> ret;
const Variable * const argvar = scope->function->getArgumentVar(argnr); const Variable * const argvar = scope->function->getArgumentVar(argnr);
if (!argvar->isPointer()) if (!argvar->isPointer() && !argvar->isReference())
return ret; return ret;
for (const Token *tok2 = scope->bodyStart; tok2 != scope->bodyEnd; tok2 = tok2->next()) { for (const Token *tok2 = scope->bodyStart; tok2 != scope->bodyEnd; tok2 = tok2->next()) {
if (Token::Match(tok2, ")|else {")) { if (Token::Match(tok2, ")|else {")) {

View File

@ -6136,6 +6136,22 @@ private:
" f(&x);\n" " f(&x);\n"
"}"); "}");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
ctu("void increment(int& i) { ++i; }\n" // #6475
"int f() {\n"
" int n;\n"
" increment(n);\n"
" return n;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:1]: (error) Using argument i that points at uninitialized variable n\n", errout.str());
ctu("void increment(int* i) { ++(*i); }\n"
"int f() {\n"
" int n;\n"
" increment(&n);\n"
" return n;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:1]: (error) Using argument i that points at uninitialized variable n\n", errout.str());
} }
}; };