[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:
Nathan Gauër 2024-03-14 11:43:44 +01:00 коммит произвёл GitHub
Родитель 5852de760b
Коммит d9bd2a706c
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
2 изменённых файлов: 85 добавлений и 3 удалений

Просмотреть файл

@ -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 };
}