[SPIR-V] Fix list initializer code (#6408)
The list initializer code was not always checking the initializer list size before reading it, causing crashes. Checking the list size led me to discover paths in which the code could crash by dereferencing null pointers. Added a few guards to check if a subpath failed before continuing. Fixes #6143 Signed-off-by: Nathan Gauër <brioche@google.com>
This commit is contained in:
Родитель
5852de760b
Коммит
d9bd2a706c
|
@ -48,7 +48,9 @@ SpirvInstruction *InitListHandler::processCast(QualType toType,
|
|||
initializers.clear();
|
||||
scalars.clear();
|
||||
|
||||
initializers.push_back(theEmitter.loadIfGLValue(expr));
|
||||
auto *initializer = theEmitter.loadIfGLValue(expr);
|
||||
if (initializer)
|
||||
initializers.push_back(initializer);
|
||||
|
||||
return doProcess(toType, expr->getExprLoc());
|
||||
}
|
||||
|
@ -294,6 +296,10 @@ InitListHandler::createInitForVectorType(QualType elemType, uint32_t count,
|
|||
while (tryToSplitStruct() || tryToSplitConstantArray())
|
||||
;
|
||||
|
||||
// Not enough elements in the initializer list. Giving up.
|
||||
if (initializers.empty())
|
||||
return nullptr;
|
||||
|
||||
auto init = initializers.back();
|
||||
const auto initType = init->getAstResultType();
|
||||
|
||||
|
@ -339,6 +345,10 @@ SpirvInstruction *InitListHandler::createInitForMatrixType(
|
|||
while (tryToSplitStruct() || tryToSplitConstantArray())
|
||||
;
|
||||
|
||||
// Not enough elements in the initializer list. Giving up.
|
||||
if (initializers.empty())
|
||||
return nullptr;
|
||||
|
||||
auto init = initializers.back();
|
||||
|
||||
if (hlsl::IsHLSLMatType(init->getAstResultType())) {
|
||||
|
@ -383,6 +393,8 @@ InitListHandler::createInitForStructType(QualType type, SourceLocation srcLoc,
|
|||
while (tryToSplitConstantArray())
|
||||
;
|
||||
|
||||
// Note: an empty initializer list can be valid. Ex: initializing an
|
||||
// empty struct.
|
||||
if (!initializers.empty()) {
|
||||
auto init = initializers.back();
|
||||
// We can only avoid decomposing and reconstructing when the type is
|
||||
|
@ -418,6 +430,8 @@ InitListHandler::createInitForStructType(QualType type, SourceLocation srcLoc,
|
|||
const QualType &fieldType,
|
||||
const StructType::FieldInfo &fieldInfo) {
|
||||
SpirvInstruction *init = createInitForType(fieldType, srcLoc, range);
|
||||
if (!init)
|
||||
return false;
|
||||
|
||||
// For non bit-fields, `init` will be the value for the component.
|
||||
if (!fieldInfo.bitfield.hasValue()) {
|
||||
|
@ -449,6 +463,10 @@ InitListHandler::createInitForStructType(QualType type, SourceLocation srcLoc,
|
|||
return true;
|
||||
},
|
||||
true);
|
||||
|
||||
for (const auto *field : fields)
|
||||
if (field == nullptr)
|
||||
return nullptr;
|
||||
return spvBuilder.createCompositeConstruct(type, fields, srcLoc, range);
|
||||
}
|
||||
|
||||
|
@ -463,6 +481,10 @@ SpirvInstruction *InitListHandler::createInitForConstantArrayType(
|
|||
while (tryToSplitStruct())
|
||||
;
|
||||
|
||||
// Not enough elements in the initializer list. Giving up.
|
||||
if (initializers.empty())
|
||||
return nullptr;
|
||||
|
||||
auto init = initializers.back();
|
||||
// We can only avoid decomposing and reconstructing when the type is
|
||||
// exactly the same.
|
||||
|
@ -485,8 +507,12 @@ SpirvInstruction *InitListHandler::createInitForConstantArrayType(
|
|||
const auto size = static_cast<uint32_t>(arrType->getSize().getZExtValue());
|
||||
|
||||
llvm::SmallVector<SpirvInstruction *, 4> elements;
|
||||
for (uint32_t i = 0; i < size; ++i)
|
||||
elements.push_back(createInitForType(elemType, srcLoc, range));
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
auto *it = createInitForType(elemType, srcLoc, range);
|
||||
if (!it)
|
||||
return nullptr;
|
||||
elements.push_back(it);
|
||||
}
|
||||
|
||||
// TODO: use OpConstantComposite when all components are constants
|
||||
return spvBuilder.createCompositeConstruct(type, elements, srcLoc, range);
|
||||
|
@ -516,6 +542,11 @@ InitListHandler::createInitForBufferOrImageType(QualType type,
|
|||
while (tryToSplitStruct() || tryToSplitConstantArray())
|
||||
;
|
||||
|
||||
// Not enough elements in the initializer list. Giving up.
|
||||
if (initializers.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto init = initializers.back();
|
||||
initializers.pop_back();
|
||||
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
// RUN: not %dxc -T cs_6_2 -E main -enable-16bit-types %s -spirv 2>&1 | FileCheck %s
|
||||
|
||||
typedef vector<uint32_t,3> uint32_t3;
|
||||
typedef vector<uint16_t,3> uint16_t3;
|
||||
uint32_t3 gl_WorkGroupSize();
|
||||
|
||||
struct S {
|
||||
float3 a;
|
||||
};
|
||||
|
||||
float3 foo();
|
||||
RWStructuredBuffer<float> bar();
|
||||
float baz();
|
||||
|
||||
struct Empty {};
|
||||
|
||||
struct B {
|
||||
float a;
|
||||
Empty b;
|
||||
};
|
||||
|
||||
[numthreads(1, 1, 1)]
|
||||
void main() {
|
||||
|
||||
// createInitForVectorType
|
||||
// CHECK: 27:20: error: found undefined function
|
||||
int4 v = int4(1, foo());
|
||||
// CHECK: 29:36: error: found undefined function
|
||||
const uint16_t3 dims = uint16_t3(gl_WorkGroupSize());
|
||||
|
||||
// createInitForMatrixType
|
||||
// CHECK: 33:21: error: found undefined function
|
||||
float2x2 m = { 0, foo() };
|
||||
|
||||
// createInitForStructType
|
||||
// CHECK: 37:13: error: found undefined function
|
||||
S s = (S)foo();
|
||||
|
||||
// createInitForConstantArrayType
|
||||
// CHECK: 41:27: error: found undefined function
|
||||
const float data[3] = { foo() };
|
||||
|
||||
// createInitForBufferOrImageType
|
||||
// CHECK: 46:38: error: found undefined function
|
||||
// CHECK: 46:36: fatal error: cannot find the associated counter variable
|
||||
RWStructuredBuffer<float> buff = { bar() };
|
||||
|
||||
// Valid empty initializer list.
|
||||
// CHECK-NOT: error
|
||||
B b = { 1.f };
|
||||
}
|
Загрузка…
Ссылка в новой задаче