spirv: Rework error checking for decorations
This reworks the error checking on our generic handling of decorations. The objective is to validate all of the SPIR-V assumptions we make up-front and convert redundant checks to compiled-out asserts. The most important part of this is to ensure that member decorations only occur on OpTypeStruct and that the member is never out-of-bounds. This way later code can assume that the member is sane and not have to worry about OOB array access due to a misplaced OpMemberDecorate. Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
This commit is contained in:
@@ -376,15 +376,27 @@ _foreach_decoration_helper(struct vtn_builder *b,
|
|||||||
if (dec->scope == VTN_DEC_DECORATION) {
|
if (dec->scope == VTN_DEC_DECORATION) {
|
||||||
member = parent_member;
|
member = parent_member;
|
||||||
} else if (dec->scope >= VTN_DEC_STRUCT_MEMBER0) {
|
} else if (dec->scope >= VTN_DEC_STRUCT_MEMBER0) {
|
||||||
vtn_assert(parent_member == -1);
|
vtn_fail_if(value->value_type != vtn_value_type_type ||
|
||||||
|
value->type->base_type != vtn_base_type_struct,
|
||||||
|
"OpMemberDecorate and OpGroupMemberDecorate are only "
|
||||||
|
"allowed on OpTypeStruct");
|
||||||
|
/* This means we haven't recursed yet */
|
||||||
|
assert(value == base_value);
|
||||||
|
|
||||||
member = dec->scope - VTN_DEC_STRUCT_MEMBER0;
|
member = dec->scope - VTN_DEC_STRUCT_MEMBER0;
|
||||||
|
|
||||||
|
vtn_fail_if(member >= base_value->type->length,
|
||||||
|
"OpMemberDecorate specifies member %d but the "
|
||||||
|
"OpTypeStruct has only %u members",
|
||||||
|
member, base_value->type->length);
|
||||||
} else {
|
} else {
|
||||||
/* Not a decoration */
|
/* Not a decoration */
|
||||||
|
assert(dec->scope == VTN_DEC_EXECUTION_MODE);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dec->group) {
|
if (dec->group) {
|
||||||
vtn_assert(dec->group->value_type == vtn_value_type_decoration_group);
|
assert(dec->group->value_type == vtn_value_type_decoration_group);
|
||||||
_foreach_decoration_helper(b, base_value, member, dec->group,
|
_foreach_decoration_helper(b, base_value, member, dec->group,
|
||||||
cb, data);
|
cb, data);
|
||||||
} else {
|
} else {
|
||||||
@@ -414,7 +426,7 @@ vtn_foreach_execution_mode(struct vtn_builder *b, struct vtn_value *value,
|
|||||||
if (dec->scope != VTN_DEC_EXECUTION_MODE)
|
if (dec->scope != VTN_DEC_EXECUTION_MODE)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
vtn_assert(dec->group == NULL);
|
assert(dec->group == NULL);
|
||||||
cb(b, value, dec, data);
|
cb(b, value, dec, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -435,7 +447,7 @@ vtn_handle_decoration(struct vtn_builder *b, SpvOp opcode,
|
|||||||
case SpvOpDecorate:
|
case SpvOpDecorate:
|
||||||
case SpvOpMemberDecorate:
|
case SpvOpMemberDecorate:
|
||||||
case SpvOpExecutionMode: {
|
case SpvOpExecutionMode: {
|
||||||
struct vtn_value *val = &b->values[target];
|
struct vtn_value *val = vtn_untyped_value(b, target);
|
||||||
|
|
||||||
struct vtn_decoration *dec = rzalloc(b, struct vtn_decoration);
|
struct vtn_decoration *dec = rzalloc(b, struct vtn_decoration);
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
@@ -444,12 +456,14 @@ vtn_handle_decoration(struct vtn_builder *b, SpvOp opcode,
|
|||||||
break;
|
break;
|
||||||
case SpvOpMemberDecorate:
|
case SpvOpMemberDecorate:
|
||||||
dec->scope = VTN_DEC_STRUCT_MEMBER0 + *(w++);
|
dec->scope = VTN_DEC_STRUCT_MEMBER0 + *(w++);
|
||||||
|
vtn_fail_if(dec->scope < VTN_DEC_STRUCT_MEMBER0, /* overflow */
|
||||||
|
"Member argument of OpMemberDecorate too large");
|
||||||
break;
|
break;
|
||||||
case SpvOpExecutionMode:
|
case SpvOpExecutionMode:
|
||||||
dec->scope = VTN_DEC_EXECUTION_MODE;
|
dec->scope = VTN_DEC_EXECUTION_MODE;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
vtn_fail("Invalid decoration opcode");
|
unreachable("Invalid decoration opcode");
|
||||||
}
|
}
|
||||||
dec->decoration = *(w++);
|
dec->decoration = *(w++);
|
||||||
dec->literals = w;
|
dec->literals = w;
|
||||||
@@ -474,6 +488,8 @@ vtn_handle_decoration(struct vtn_builder *b, SpvOp opcode,
|
|||||||
dec->scope = VTN_DEC_DECORATION;
|
dec->scope = VTN_DEC_DECORATION;
|
||||||
} else {
|
} else {
|
||||||
dec->scope = VTN_DEC_STRUCT_MEMBER0 + *(++w);
|
dec->scope = VTN_DEC_STRUCT_MEMBER0 + *(++w);
|
||||||
|
vtn_fail_if(dec->scope < 0, /* Check for overflow */
|
||||||
|
"Member argument of OpGroupMemberDecorate too large");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Link into the list */
|
/* Link into the list */
|
||||||
@@ -484,7 +500,7 @@ vtn_handle_decoration(struct vtn_builder *b, SpvOp opcode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
vtn_fail("Unhandled opcode");
|
unreachable("Unhandled opcode");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -561,7 +577,7 @@ struct_member_decoration_cb(struct vtn_builder *b,
|
|||||||
if (member < 0)
|
if (member < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
vtn_assert(member < ctx->num_fields);
|
assert(member < ctx->num_fields);
|
||||||
|
|
||||||
switch (dec->decoration) {
|
switch (dec->decoration) {
|
||||||
case SpvDecorationNonWritable:
|
case SpvDecorationNonWritable:
|
||||||
@@ -664,7 +680,10 @@ struct_member_matrix_stride_cb(struct vtn_builder *b,
|
|||||||
{
|
{
|
||||||
if (dec->decoration != SpvDecorationMatrixStride)
|
if (dec->decoration != SpvDecorationMatrixStride)
|
||||||
return;
|
return;
|
||||||
vtn_assert(member >= 0);
|
|
||||||
|
vtn_fail_if(member < 0,
|
||||||
|
"The MatrixStride decoration is only allowed on members "
|
||||||
|
"of OpTypeStruct");
|
||||||
|
|
||||||
struct member_decoration_ctx *ctx = void_ctx;
|
struct member_decoration_ctx *ctx = void_ctx;
|
||||||
|
|
||||||
@@ -686,8 +705,12 @@ type_decoration_cb(struct vtn_builder *b,
|
|||||||
{
|
{
|
||||||
struct vtn_type *type = val->type;
|
struct vtn_type *type = val->type;
|
||||||
|
|
||||||
if (member != -1)
|
if (member != -1) {
|
||||||
|
/* This should have been handled by OpTypeStruct */
|
||||||
|
assert(val->type->base_type == vtn_base_type_struct);
|
||||||
|
assert(member >= 0 && member < val->type->length);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (dec->decoration) {
|
switch (dec->decoration) {
|
||||||
case SpvDecorationArrayStride:
|
case SpvDecorationArrayStride:
|
||||||
|
Reference in New Issue
Block a user