Skip to content

Commit 1de6af8

Browse files
Fix #12685 FN uninitvar for constructor argument (#6368)
1 parent 858b5ea commit 1de6af8

2 files changed

Lines changed: 45 additions & 9 deletions

File tree

lib/astutils.cpp

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3295,15 +3295,36 @@ static ExprUsage getFunctionUsage(const Token* tok, int indirect, const Settings
32953295
const Token* ftok = getTokenArgumentFunction(tok, argnr);
32963296
if (!ftok)
32973297
return ExprUsage::None;
3298-
if (ftok->function()) {
3298+
const Function* func = ftok->function();
3299+
// variable init/constructor call?
3300+
if (!func && ftok->variable() && ftok == ftok->variable()->nameToken()) {
3301+
// STL types or containers don't initialize external variables
3302+
if (ftok->variable()->isStlType() || (ftok->variable()->valueType() && ftok->variable()->valueType()->container))
3303+
return ExprUsage::Used;
3304+
// TODO: resolve multiple constructors
3305+
if (ftok->variable()->type() && ftok->variable()->type()->classScope) {
3306+
const int nCtor = ftok->variable()->type()->classScope->numConstructors;
3307+
if (nCtor == 0)
3308+
return ExprUsage::Used;
3309+
if (nCtor == 1) {
3310+
const Scope* scope = ftok->variable()->type()->classScope;
3311+
auto it = std::find_if(scope->functionList.begin(), scope->functionList.end(), [](const Function& f) {
3312+
return f.isConstructor();
3313+
});
3314+
if (it != scope->functionList.end())
3315+
func = &*it;
3316+
}
3317+
}
3318+
}
3319+
if (func) {
32993320
std::vector<const Variable*> args = getArgumentVars(ftok, argnr);
33003321
for (const Variable* arg : args) {
33013322
if (!arg)
33023323
continue;
33033324
if (arg->isReference() || (arg->isPointer() && indirect == 1)) {
3304-
if (!ftok->function()->hasBody())
3325+
if (!func->hasBody())
33053326
return ExprUsage::PassedByReference;
3306-
for (const Token* bodytok = ftok->function()->functionScope->bodyStart; bodytok != ftok->function()->functionScope->bodyEnd; bodytok = bodytok->next()) {
3327+
for (const Token* bodytok = func->functionScope->bodyStart; bodytok != func->functionScope->bodyEnd; bodytok = bodytok->next()) {
33073328
if (bodytok->variable() == arg) {
33083329
if (arg->isReference())
33093330
return ExprUsage::PassedByReference;
@@ -3321,11 +3342,6 @@ static ExprUsage getFunctionUsage(const Token* tok, int indirect, const Settings
33213342
return ExprUsage::Used;
33223343
} else if (ftok->str() == "{") {
33233344
return indirect == 0 ? ExprUsage::Used : ExprUsage::Inconclusive;
3324-
} else if (ftok->variable() && ftok == ftok->variable()->nameToken()) { // variable init/constructor call
3325-
if (ftok->variable()->type() && ftok->variable()->type()->classScope && ftok->variable()->type()->classScope->numConstructors == 0)
3326-
return ExprUsage::Used;
3327-
if (ftok->variable()->isStlType() || (ftok->variable()->valueType() && ftok->variable()->valueType()->container)) // STL types or containers don't initialize external variables
3328-
return ExprUsage::Used;
33293345
} else {
33303346
const bool isnullbad = settings.library.isnullargbad(ftok, argnr + 1);
33313347
if (indirect == 0 && astIsPointer(tok) && !addressOf && isnullbad)

test/testuninitvar.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7438,7 +7438,7 @@ class TestUninitVar : public TestFixture {
74387438
"[test.cpp:27]: (error) Uninitialized variable: s.t.j\n",
74397439
errout_str());
74407440

7441-
valueFlowUninit("struct S { int x; };\n"
7441+
valueFlowUninit("struct S { int x; };\n" // #6933
74427442
"void f() {\n"
74437443
" int i;\n"
74447444
" S s(i);\n"
@@ -7525,6 +7525,26 @@ class TestUninitVar : public TestFixture {
75257525
" return s2;\n"
75267526
"}\n");
75277527
ASSERT_EQUALS("", errout_str());
7528+
7529+
valueFlowUninit("struct S {\n" // #12685
7530+
" explicit S(double v);\n"
7531+
" double m;\n"
7532+
"};\n"
7533+
"void f() {\n"
7534+
" double d;\n"
7535+
" S s(d);\n"
7536+
"}\n");
7537+
ASSERT_EQUALS("[test.cpp:7]: (error) Uninitialized variable: d\n", errout_str());
7538+
7539+
valueFlowUninit("struct S {\n"
7540+
" explicit S(double v) : m(v) {}\n"
7541+
" double m;\n"
7542+
"};\n"
7543+
"void f() {\n"
7544+
" double d;\n"
7545+
" S s{ d };\n"
7546+
"}\n");
7547+
ASSERT_EQUALS("[test.cpp:7]: (error) Uninitialized variable: d\n", errout_str());
75287548
}
75297549

75307550
void uninitvar_memberfunction() {

0 commit comments

Comments
 (0)