spirv-opt: Handle ID overflow in SplitCombinedImageSamplerPass (#6406)
This pass creates new instructions without checking if the new IDs will
overflow. This can lead to a crash if the module has many IDs.
This CL adds checks for ID overflow and returns an error if it happens.
diff --git a/source/opt/split_combined_image_sampler_pass.cpp b/source/opt/split_combined_image_sampler_pass.cpp
index 338320d..b5d3d65 100644
--- a/source/opt/split_combined_image_sampler_pass.cpp
+++ b/source/opt/split_combined_image_sampler_pass.cpp
@@ -142,6 +142,7 @@
analysis::Sampler s;
uint32_t sampler_type_id = type_mgr_->GetTypeInstruction(&s);
sampler_type_ = def_use_mgr_->GetDef(sampler_type_id);
+ if (sampler_type_ == nullptr) return nullptr;
assert(first_sampled_image_type_);
sampler_type_->InsertBefore(first_sampled_image_type_);
RegisterNewGlobal(sampler_type_->result_id());
@@ -169,6 +170,7 @@
auto* image_type =
def_use_mgr_->GetDef(combined_kind_type.GetSingleWordInOperand(0));
auto* sampler_type = GetSamplerType();
+ if (!sampler_type) return {nullptr, nullptr};
type_remap_[combined_kind_type.result_id()] = {&combined_kind_type,
image_type, sampler_type};
return {image_type, sampler_type};
@@ -187,7 +189,9 @@
// this defensively.
if (image_pointee && sampler_pointee) {
auto* ptr_image = MakeUniformConstantPointer(image_pointee);
+ if (!ptr_image) return {nullptr, nullptr};
auto* ptr_sampler = MakeUniformConstantPointer(sampler_pointee);
+ if (!ptr_sampler) return {nullptr, nullptr};
type_remap_[combined_kind_type.result_id()] = {
&combined_kind_type, ptr_image, ptr_sampler};
return {ptr_image, ptr_sampler};
@@ -207,6 +211,7 @@
analysis::Array array_image_ty(image_ty, array_ty->length_info());
const uint32_t array_image_ty_id =
type_mgr_->GetTypeInstruction(&array_image_ty);
+ if (array_image_ty_id == 0) return {nullptr, nullptr};
auto* array_image_ty_inst = def_use_mgr_->GetDef(array_image_ty_id);
if (!IsKnownGlobal(array_image_ty_id)) {
array_image_ty_inst->InsertBefore(&combined_kind_type);
@@ -214,11 +219,14 @@
// GetTypeInstruction also updated the def-use manager.
}
+ auto* sampler_ty_inst = GetSamplerType();
+ if (!sampler_ty_inst) return {nullptr, nullptr};
analysis::Array sampler_array_ty(
- type_mgr_->GetType(GetSamplerType()->result_id()),
+ type_mgr_->GetType(sampler_ty_inst->result_id()),
array_ty->length_info());
const uint32_t array_sampler_ty_id =
type_mgr_->GetTypeInstruction(&sampler_array_ty);
+ if (array_sampler_ty_id == 0) return {nullptr, nullptr};
auto* array_sampler_ty_inst = def_use_mgr_->GetDef(array_sampler_ty_id);
if (!IsKnownGlobal(array_sampler_ty_id)) {
array_sampler_ty_inst->InsertBefore(&combined_kind_type);
@@ -240,6 +248,7 @@
analysis::RuntimeArray array_image_ty(image_ty);
const uint32_t array_image_ty_id =
type_mgr_->GetTypeInstruction(&array_image_ty);
+ if (array_image_ty_id == 0) return {nullptr, nullptr};
auto* array_image_ty_inst = def_use_mgr_->GetDef(array_image_ty_id);
if (!IsKnownGlobal(array_image_ty_id)) {
array_image_ty_inst->InsertBefore(&combined_kind_type);
@@ -247,10 +256,13 @@
// GetTypeInstruction also updated the def-use manager.
}
+ auto* sampler_ty_inst = GetSamplerType();
+ if (!sampler_ty_inst) return {nullptr, nullptr};
analysis::RuntimeArray sampler_array_ty(
- type_mgr_->GetType(GetSamplerType()->result_id()));
+ type_mgr_->GetType(sampler_ty_inst->result_id()));
const uint32_t array_sampler_ty_id =
type_mgr_->GetTypeInstruction(&sampler_array_ty);
+ if (array_sampler_ty_id == 0) return {nullptr, nullptr};
auto* array_sampler_ty_inst = def_use_mgr_->GetDef(array_sampler_ty_id);
if (!IsKnownGlobal(array_sampler_ty_id)) {
array_sampler_ty_inst->InsertBefore(&combined_kind_type);
@@ -273,14 +285,14 @@
// Create an image variable, and a sampler variable.
auto* combined_var_type = def_use_mgr_->GetDef(combined_var->type_id());
auto [ptr_image_ty, ptr_sampler_ty] = SplitType(*combined_var_type);
- assert(ptr_image_ty);
- assert(ptr_sampler_ty);
- // TODO(1841): Handle id overflow.
+ if (!ptr_image_ty || !ptr_sampler_ty) return SPV_ERROR_INTERNAL;
Instruction* sampler_var = builder.AddVariable(
ptr_sampler_ty->result_id(), SpvStorageClassUniformConstant);
- // TODO(1841): Handle id overflow.
+ if (sampler_var == nullptr) return SPV_ERROR_INTERNAL;
Instruction* image_var = builder.AddVariable(ptr_image_ty->result_id(),
SpvStorageClassUniformConstant);
+ if (image_var == nullptr) return SPV_ERROR_INTERNAL;
+
modified_ = true;
return RemapUses(combined_var, image_var, sampler_var);
}
@@ -356,12 +368,12 @@
// Create loads for the image part and sampler part.
builder.SetInsertPoint(load);
- // TODO(1841): Handle id overflow.
auto* image = builder.AddLoad(PointeeTypeId(use.image_part),
use.image_part->result_id());
- // TODO(1841): Handle id overflow.
+ if (!image) return SPV_ERROR_INTERNAL;
auto* sampler = builder.AddLoad(PointeeTypeId(use.sampler_part),
use.sampler_part->result_id());
+ if (!sampler) return SPV_ERROR_INTERNAL;
// Move decorations, such as RelaxedPrecision.
auto* deco_mgr = context()->get_decoration_mgr();
@@ -372,6 +384,7 @@
// Create a sampled image from the loads of the two parts.
auto* sampled_image = builder.AddSampledImage(
load->type_id(), image->result_id(), sampler->result_id());
+ if (!sampled_image) return SPV_ERROR_INTERNAL;
// Replace the original sampled image value with the new one.
std::unordered_set<Instruction*> users;
def_use_mgr_->ForEachUse(
@@ -463,14 +476,18 @@
auto [result_image_part_ty, result_sampler_part_ty] =
SplitType(*def_use_mgr_->GetDef(original_access_chain->type_id()));
- // TODO(1841): Handle id overflow.
+ if (!result_image_part_ty || !result_sampler_part_ty)
+ return Fail() << "failed to split type for access chain";
auto* result_image_part = builder.AddOpcodeAccessChain(
use.user->opcode(), result_image_part_ty->result_id(),
use.image_part->result_id(), indices);
- // TODO(1841): Handle id overflow.
+ if (!result_image_part)
+ return Fail() << "failed to create access chain for image part";
auto* result_sampler_part = builder.AddOpcodeAccessChain(
use.user->opcode(), result_sampler_part_ty->result_id(),
use.sampler_part->result_id(), indices);
+ if (!result_sampler_part)
+ return Fail() << "failed to create access chain for sampler part";
// Remap uses of the original access chain.
add_remap(original_access_chain, result_image_part,
@@ -521,8 +538,7 @@
if (combined_types_.find(param_ty_id) != combined_types_.end()) {
auto* param_type = def_use_mgr_->GetDef(param_ty_id);
auto [image_type, sampler_type] = SplitType(*param_type);
- assert(image_type);
- assert(sampler_type);
+ if (!image_type || !sampler_type) return SPV_ERROR_INTERNAL;
// The image and sampler types must already exist, so there is no
// need to move them to the right spot.
new_params.push_back(type_mgr_->GetType(image_type->result_id()));
@@ -579,6 +595,11 @@
auto* combined_inst = param.release();
auto* combined_type = def_use_mgr_->GetDef(combined_inst->type_id());
auto [image_type, sampler_type] = SplitType(*combined_type);
+ if (!image_type || !sampler_type) {
+ error = true;
+ return;
+ }
+
uint32_t image_param_id = context()->TakeNextId();
if (image_param_id == 0) {
error = true;
@@ -621,6 +642,7 @@
Instruction* pointee) {
uint32_t ptr_id = type_mgr_->FindPointerToType(
pointee->result_id(), spv::StorageClass::UniformConstant);
+ if (ptr_id == 0) return nullptr;
auto* ptr = def_use_mgr_->GetDef(ptr_id);
if (!IsKnownGlobal(ptr_id)) {
// The pointer type was created at the end. Put it right after the