Skip to content

Commit b6b31e7

Browse files
authored
[analyzer] Fix uninitialized base class with initializer list when ctor is not declared in the base class
Fixes #70464 When ctor is not declared in the base class, initializing the base class with the initializer list will not trigger a proper assignment of the base region, as a CXXConstructExpr doing that is not available in the AST. This patch checks whether the init expr is an InitListExpr under a base initializer, and adds a binding if so.
1 parent 6b8ed78 commit b6b31e7

File tree

2 files changed

+76
-0
lines changed

2 files changed

+76
-0
lines changed

clang/lib/StaticAnalyzer/Core/ExprEngine.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1222,6 +1222,14 @@ void ExprEngine::ProcessInitializer(const CFGInitializer CFGInit,
12221222
PostInitializer PP(BMI, FieldLoc.getAsRegion(), stackFrame);
12231223
evalBind(Tmp, Init, Pred, FieldLoc, InitVal, /*isInit=*/true, &PP);
12241224
}
1225+
} else if (BMI->isBaseInitializer() && isa<InitListExpr>(Init)) {
1226+
// When the base class is initialized with an initialization list and the
1227+
// base class does not have a ctor, there will not be a CXXConstructExpr to
1228+
// initialize the base region. Hence, we need to make the bind for it.
1229+
SVal BaseLoc = getStoreManager().evalDerivedToBase(
1230+
thisVal, QualType(BMI->getBaseClass(), 0), BMI->isBaseVirtual());
1231+
SVal InitVal = State->getSVal(Init, stackFrame);
1232+
evalBind(Tmp, Init, Pred, BaseLoc, InitVal, /*isInit=*/true);
12251233
} else {
12261234
assert(BMI->isBaseInitializer() || BMI->isDelegatingInitializer());
12271235
Tmp.insert(Pred);

clang/test/Analysis/issue-70464.cpp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// RUN: %clang_analyze_cc1 %s -verify -analyzer-checker=core,debug.ExprInspection
2+
3+
// Refer to https://github.com/llvm/llvm-project/issues/70464 for more details.
4+
//
5+
// When the base class does not have a declared constructor, the base
6+
// initializer in the constructor of the derived class should use the given
7+
// initializer list to finish the initialization of the base class.
8+
//
9+
// Also testing base constructor and delegate constructor to make sure this
10+
// change will not break these two cases when a CXXConstructExpr is available.
11+
12+
void clang_analyzer_dump(int);
13+
14+
namespace init_list {
15+
16+
struct Base {
17+
int foox;
18+
};
19+
20+
class Derived : public Base {
21+
public:
22+
Derived() : Base{42} {
23+
// The dereference to this->foox below should be initialized properly.
24+
clang_analyzer_dump(this->foox); // expected-warning{{42 S32b}}
25+
clang_analyzer_dump(foox); // expected-warning{{42 S32b}}
26+
}
27+
};
28+
29+
void entry() { Derived test; }
30+
31+
} // namespace init_list
32+
33+
namespace base_ctor_call {
34+
35+
struct Base {
36+
int foox;
37+
Base(int x) : foox(x) {}
38+
};
39+
40+
class Derived : public Base {
41+
public:
42+
Derived() : Base{42} {
43+
clang_analyzer_dump(this->foox); // expected-warning{{42 S32b}}
44+
clang_analyzer_dump(foox); // expected-warning{{42 S32b}}
45+
}
46+
};
47+
48+
void entry() { Derived test; }
49+
50+
} // namespace base_ctor_call
51+
52+
namespace delegate_ctor_call {
53+
54+
struct Base {
55+
int foox;
56+
};
57+
58+
struct Derived : Base {
59+
Derived(int parx) { this->foox = parx; }
60+
Derived() : Derived{42} {
61+
clang_analyzer_dump(this->foox); // expected-warning{{42 S32b}}
62+
clang_analyzer_dump(foox); // expected-warning{{42 S32b}}
63+
}
64+
};
65+
66+
void entry() { Derived test; }
67+
68+
} // namespace delegate_ctor_call

0 commit comments

Comments
 (0)