Fix checks for offset in nested structs (#4531)

Fixes #4533
Fixes https://crbug.com/38771

* Fixes offset checks to look through arrays for nested structures
This commit is contained in:
alan-baker 2021-09-21 11:15:16 -04:00 committed by GitHub
parent 0f4508752f
commit a6c5056db2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 53 additions and 9 deletions

View File

@ -129,18 +129,28 @@ std::vector<uint32_t> getStructMembers(uint32_t struct_id, SpvOp type,
// Returns whether the given structure is missing Offset decoration for any
// member. Handles also nested structures.
bool isMissingOffsetInStruct(uint32_t struct_id, ValidationState_t& vstate) {
std::vector<bool> hasOffset(getStructMembers(struct_id, vstate).size(),
false);
// Check offsets of member decorations
for (auto& decoration : vstate.id_decorations(struct_id)) {
if (SpvDecorationOffset == decoration.dec_type() &&
Decoration::kInvalidMember != decoration.struct_member_index()) {
hasOffset[decoration.struct_member_index()] = true;
const auto* inst = vstate.FindDef(struct_id);
std::vector<bool> hasOffset;
std::vector<uint32_t> struct_members;
if (inst->opcode() == SpvOpTypeStruct) {
// Check offsets of member decorations.
struct_members = getStructMembers(struct_id, vstate);
hasOffset.resize(struct_members.size(), false);
for (auto& decoration : vstate.id_decorations(struct_id)) {
if (SpvDecorationOffset == decoration.dec_type() &&
Decoration::kInvalidMember != decoration.struct_member_index()) {
hasOffset[decoration.struct_member_index()] = true;
}
}
} else if (inst->opcode() == SpvOpTypeArray ||
inst->opcode() == SpvOpTypeRuntimeArray) {
hasOffset.resize(1, true);
struct_members.push_back(inst->GetOperandAs<uint32_t>(1u));
}
// Check also nested structures
// Look through nested structs (which may be in an array).
bool nestedStructsMissingOffset = false;
for (auto id : getStructMembers(struct_id, SpvOpTypeStruct, vstate)) {
for (auto id : struct_members) {
if (isMissingOffsetInStruct(id, vstate)) {
nestedStructsMissingOffset = true;
break;

View File

@ -7791,6 +7791,40 @@ OpFunctionEnd
"member 0 is a matrix with stride 3 not satisfying alignment to 4"));
}
TEST_F(ValidateDecorations, MissingOffsetStructNestedInArray) {
const std::string spirv = R"(
OpCapability Shader
OpExtension "SPV_KHR_storage_buffer_storage_class"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpDecorate %array ArrayStride 4
OpDecorate %outer Block
OpMemberDecorate %outer 0 Offset 0
OpDecorate %var DescriptorSet 0
OpDecorate %var Binding 0
%void = OpTypeVoid
%int = OpTypeInt 32 0
%int_4 = OpConstant %int 4
%inner = OpTypeStruct %int
%array = OpTypeArray %inner %int_4
%outer = OpTypeStruct %array
%ptr_ssbo_outer = OpTypePointer StorageBuffer %outer
%var = OpVariable %ptr_ssbo_outer StorageBuffer
%void_fn = OpTypeFunction %void
%main = OpFunction %void None %void_fn
%entry = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Structure id 3 decorated as Block must be explicitly "
"laid out with Offset decorations"));
}
} // namespace
} // namespace val
} // namespace spvtools