Skip to content

Commit db6f5d6

Browse files
committed
share initializer list modeling between VisitInitListExpr and VisitCXXParenListInitExpr
1 parent 64de252 commit db6f5d6

File tree

5 files changed

+96
-71
lines changed

5 files changed

+96
-71
lines changed

clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,10 @@ class ExprEngine {
594594
ExplodedNode *Pred,
595595
ExplodedNodeSet &Dst);
596596

597+
void CreateInitializationList(const Expr *Source, ArrayRef<Expr *> Args,
598+
bool IsTransparent, ExplodedNode *Pred,
599+
ExplodedNodeSet &Dst);
600+
597601
/// evalEagerlyAssumeBifurcation - Given the nodes in 'Src', eagerly assume
598602
/// concrete boolean values for 'Ex', storing the resulting nodes in 'Dst'.
599603
void evalEagerlyAssumeBifurcation(ExplodedNodeSet &Dst, ExplodedNodeSet &Src,

clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp

Lines changed: 34 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -774,49 +774,7 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
774774
void ExprEngine::VisitInitListExpr(const InitListExpr *IE,
775775
ExplodedNode *Pred,
776776
ExplodedNodeSet &Dst) {
777-
StmtNodeBuilder B(Pred, Dst, *currBldrCtx);
778-
779-
ProgramStateRef state = Pred->getState();
780-
const LocationContext *LCtx = Pred->getLocationContext();
781-
QualType T = getContext().getCanonicalType(IE->getType());
782-
unsigned NumInitElements = IE->getNumInits();
783-
784-
if (!IE->isGLValue() && !IE->isTransparent() &&
785-
(T->isArrayType() || T->isRecordType() || T->isVectorType() ||
786-
T->isAnyComplexType())) {
787-
llvm::ImmutableList<SVal> vals = getBasicVals().getEmptySValList();
788-
789-
// Handle base case where the initializer has no elements.
790-
// e.g: static int* myArray[] = {};
791-
if (NumInitElements == 0) {
792-
SVal V = svalBuilder.makeCompoundVal(T, vals);
793-
B.generateNode(IE, Pred, state->BindExpr(IE, LCtx, V));
794-
return;
795-
}
796-
797-
for (const Stmt *S : llvm::reverse(*IE)) {
798-
SVal V = state->getSVal(cast<Expr>(S), LCtx);
799-
vals = getBasicVals().prependSVal(V, vals);
800-
}
801-
802-
B.generateNode(IE, Pred,
803-
state->BindExpr(IE, LCtx,
804-
svalBuilder.makeCompoundVal(T, vals)));
805-
return;
806-
}
807-
808-
// Handle scalars: int{5} and int{} and GLvalues.
809-
// Note, if the InitListExpr is a GLvalue, it means that there is an address
810-
// representing it, so it must have a single init element.
811-
assert(NumInitElements <= 1);
812-
813-
SVal V;
814-
if (NumInitElements == 0)
815-
V = getSValBuilder().makeZeroVal(T);
816-
else
817-
V = state->getSVal(IE->getInit(0), LCtx);
818-
819-
B.generateNode(IE, Pred, state->BindExpr(IE, LCtx, V));
777+
CreateInitializationList(IE, IE->inits(), IE->isTransparent(), Pred, Dst);
820778
}
821779

822780
void ExprEngine::VisitGuardedExpr(const Expr *Ex,
@@ -1197,3 +1155,36 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U,
11971155
}
11981156
Dst.insert(Dst2);
11991157
}
1158+
1159+
void ExprEngine::CreateInitializationList(const Expr *E, ArrayRef<Expr *> Args,
1160+
bool IsTransparent,
1161+
ExplodedNode *Pred,
1162+
ExplodedNodeSet &Dst) {
1163+
assert((isa<InitListExpr>(E) || isa<CXXParenListInitExpr>(E)) &&
1164+
"Expected InitListExpr or CXXParenListInitExpr");
1165+
1166+
const LocationContext *LC = Pred->getLocationContext();
1167+
1168+
StmtNodeBuilder B(Pred, Dst, *currBldrCtx);
1169+
ProgramStateRef S = Pred->getState();
1170+
QualType T = E->getType().getCanonicalType();
1171+
1172+
bool IsCompound =
1173+
E->isPRValue() && (T->isArrayType() || T->isRecordType() ||
1174+
T->isAnyComplexType() || T->isVectorType());
1175+
1176+
if (Args.size() > 1 || (IsCompound && !IsTransparent)) {
1177+
llvm::ImmutableList<SVal> ArgList = getBasicVals().getEmptySValList();
1178+
for (Expr *E : llvm::reverse(Args))
1179+
ArgList = getBasicVals().prependSVal(S->getSVal(E, LC), ArgList);
1180+
1181+
B.generateNode(E, Pred,
1182+
S->BindExpr(E, LC, svalBuilder.makeCompoundVal(T, ArgList)));
1183+
} else {
1184+
B.generateNode(E, Pred,
1185+
S->BindExpr(E, LC,
1186+
Args.size() == 0
1187+
? getSValBuilder().makeZeroVal(T)
1188+
: S->getSVal(Args.front(), LC)));
1189+
}
1190+
}

clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1237,27 +1237,6 @@ void ExprEngine::VisitAttributedStmt(const AttributedStmt *A,
12371237
void ExprEngine::VisitCXXParenListInitExpr(const CXXParenListInitExpr *E,
12381238
ExplodedNode *Pred,
12391239
ExplodedNodeSet &Dst) {
1240-
const LocationContext *LC = Pred->getLocationContext();
1241-
1242-
StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
1243-
ProgramStateRef S = Pred->getState();
1244-
1245-
QualType T = E->getType().getCanonicalType();
1246-
ArrayRef<Expr *> Inits = E->getInitExprs();
1247-
1248-
if (Inits.size() > 1 ||
1249-
(E->isPRValue() && (T->isRecordType() || T->isArrayType()))) {
1250-
llvm::ImmutableList<SVal> ArgList = getBasicVals().getEmptySValList();
1251-
for (Expr *E : llvm::reverse(Inits))
1252-
ArgList = getBasicVals().prependSVal(S->getSVal(E, LC), ArgList);
1253-
1254-
Bldr.generateNode(
1255-
E, Pred, S->BindExpr(E, LC, svalBuilder.makeCompoundVal(T, ArgList)));
1256-
} else {
1257-
Bldr.generateNode(E, Pred,
1258-
S->BindExpr(E, LC,
1259-
Inits.size() == 0
1260-
? getSValBuilder().makeZeroVal(T)
1261-
: S->getSVal(Inits.front(), LC)));
1262-
}
1240+
CreateInitializationList(E, E->getInitExprs(), /*IsTransparent*/ false, Pred,
1241+
Dst);
12631242
}

clang/test/Analysis/div-zero-cxx20.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,27 +26,27 @@ struct E {
2626
};
2727

2828
int t1() {
29-
A a(42);
29+
A a{42};
3030
return 1 / (a.x - 42); // expected-warning {{Division by zero}}
3131
}
3232

3333
int t2() {
34-
B b;
34+
B b{};
3535
return 1 / b.x; // expected-warning {{Division by zero}}
3636
}
3737

3838
int t3() {
39-
C c1(1, -1);
39+
C c1{1, -1};
4040
return 1 / (c1.x + c1.y); // expected-warning {{Division by zero}}
4141
}
4242

4343
int t4() {
44-
C c2(0, 0);
44+
C c2{0, 0};
4545
return 1 / (c2.x + c2.y); // expected-warning {{Division by zero}}
4646
}
4747

4848
int t5() {
49-
E e = 32;
49+
E e{32};
5050
return 1 / (e.d.x - 32); // expected-warning {{Division by zero}}
5151
}
5252
} // namespace GH148875

clang/test/Analysis/div-zero.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,54 @@ int fooPR10616 (int qX ) {
1111
return (a % (qX-1)); // expected-warning {{Division by zero}}
1212

1313
}
14+
15+
namespace GH148875 {
16+
struct A {
17+
int x;
18+
A(int v) : x(v) {}
19+
};
20+
21+
struct B {
22+
int x;
23+
B() : x(0) {}
24+
};
25+
26+
struct C {
27+
int x, y;
28+
C(int a, int b) : x(a), y(b) {}
29+
};
30+
31+
struct D {
32+
int x;
33+
};
34+
35+
struct E {
36+
D d;
37+
E(int a) : d{a} {}
38+
};
39+
40+
int t1() {
41+
A a{42};
42+
return 1 / (a.x - 42); // expected-warning {{Division by zero}}
43+
}
44+
45+
int t2() {
46+
B b{};
47+
return 1 / b.x; // expected-warning {{Division by zero}}
48+
}
49+
50+
int t3() {
51+
C c1{1, -1};
52+
return 1 / (c1.x + c1.y); // expected-warning {{Division by zero}}
53+
}
54+
55+
int t4() {
56+
C c2{0, 0};
57+
return 1 / (c2.x + c2.y); // expected-warning {{Division by zero}}
58+
}
59+
60+
int t5() {
61+
E e{32};
62+
return 1 / (e.d.x - 32); // expected-warning {{Division by zero}}
63+
}
64+
}

0 commit comments

Comments
 (0)