Skip to content

Commit a4e16b8

Browse files
author
Tim Corringham
committed
Add defensive checks for declToIndex entries
Check the variable is in the declToIndex map before calling reportUse() for that variable or marking it as Initialized. HLSL out parameters or local variables from template instantiations may not be in the declToIndex map in the current DeclContext, which can lead to asserts when they are enabled, or the use of unitialized memory otherwise. Fixes #5293 Fixes #8310
1 parent c763461 commit a4e16b8

2 files changed

Lines changed: 89 additions & 3 deletions

File tree

tools/clang/lib/Analysis/UninitializedValues.cpp

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,12 @@ class CFGBlockValues {
171171
return declToIndex.getHLSLOutParams();
172172
}
173173
// HLSL Change End - Treat `out` parameters as uninitialized values.
174+
175+
// HLSL Change Begin - check the variable is in the declToIndex map
176+
bool hasValueIndex(const VarDecl *vd) {
177+
return declToIndex.getValueIndex(vd).hasValue();
178+
}
179+
// HLSL Change End - check the variable is in the declToIndex map
174180
};
175181
} // end anonymous namespace
176182

@@ -781,10 +787,23 @@ void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) {
781787
case ClassifyRefs::Ignore:
782788
break;
783789
case ClassifyRefs::Use:
784-
reportUse(dr, cast<VarDecl>(dr->getDecl()));
790+
// HLSL Change Begin - check the variable is in the declToIndex map
791+
// before calling reportUse(). HLSL out parameters or local variables from
792+
// template instantiations may not be mapped in the current DeclContext.
793+
if (const VarDecl *VD = cast<VarDecl>(dr->getDecl())) {
794+
if (vals.hasValueIndex(VD))
795+
reportUse(dr, VD);
796+
}
797+
// HLSL Change End - check the variable is in the declToIndex map
785798
break;
786799
case ClassifyRefs::Init:
787-
vals[cast<VarDecl>(dr->getDecl())] = Initialized;
800+
// HLSL Change Begin - check the variable is in the declToIndex map
801+
// before marking it Initialized.
802+
if (const VarDecl *VD = cast<VarDecl>(dr->getDecl())) {
803+
if (vals.hasValueIndex(VD))
804+
vals[VD] = Initialized;
805+
}
806+
// HLSL Change End - check the variable is in the declToIndex map
788807
break;
789808
case ClassifyRefs::SelfInit:
790809
handler.handleSelfInit(cast<VarDecl>(dr->getDecl()));
@@ -795,8 +814,12 @@ void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) {
795814
void TransferFunctions::VisitBinaryOperator(BinaryOperator *BO) {
796815
if (BO->getOpcode() == BO_Assign) {
797816
FindVarResult Var = findVar(BO->getLHS());
817+
// HLSL Change Begin - check the variable is in the declToIndex map
818+
// before marking it Initialized.
798819
if (const VarDecl *VD = Var.getDecl())
799-
vals[VD] = Initialized;
820+
if (vals.hasValueIndex(VD))
821+
vals[VD] = Initialized;
822+
// HLSL Change End - check the variable is in the declToIndex map
800823
}
801824
}
802825

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// RUN: dxc -E main -T cs_6_6 -HV 2021 -Wno-unused-value %s | FileCheck %s
2+
3+
// Asserts in UnitializedValues.cpp were triggered by the following code
4+
// examples. The cause was that HLSL out parameters or local variables from
5+
// template instantiations may not be present in the declToIndex map when the
6+
// variable's DeclContext differs from the analysis context (common in
7+
// template instantiations).
8+
// The fix was to add defensive checks so that if the variable isn't tracked
9+
// it is silently ignored.
10+
11+
// CHECK: define void @main()
12+
13+
template <typename R>
14+
void test(R x, out uint result) {
15+
uint repro = 0;
16+
result = 10;
17+
}
18+
19+
[numthreads(32, 32, 1)] void main(uint2 threadId: SV_DispatchThreadID) {
20+
uint x;
21+
test(10, x);
22+
}
23+
24+
template <typename NameType>
25+
void func2(out uint var1)
26+
{
27+
uint var3;
28+
uint var4;
29+
uint var5;
30+
uint var6;
31+
uint var7;
32+
uint var8;
33+
uint var9;
34+
uint var10;
35+
uint var11;
36+
uint var12;
37+
uint var13;
38+
uint var14;
39+
uint var15;
40+
uint var16;
41+
uint var17;
42+
uint var18;
43+
uint var19;
44+
uint var20;
45+
uint var21;
46+
uint var22;
47+
uint var23;
48+
uint var24;
49+
uint var25;
50+
uint var26;
51+
uint var27;
52+
uint var28;
53+
uint var29;
54+
uint var30;
55+
uint var31;
56+
var1;
57+
}
58+
59+
void func1()
60+
{
61+
uint var33;
62+
func2<uint>(var33);
63+
}

0 commit comments

Comments
 (0)