[Mesa-dev] [PATCH] nir/spirv: fix crashes when dereferencing a pointer for an OpVariable

Jason Ekstrand jason at jlekstrand.net
Mon Sep 11 16:12:51 UTC 2017


On Mon, Sep 11, 2017 at 1:42 AM, Samuel Iglesias Gonsálvez <
siglesias at igalia.com> wrote:

>
>
> On 09/07/2017 07:15 PM, Jason Ekstrand wrote:
>
> On Tue, Aug 29, 2017 at 3:04 AM, Samuel Iglesias Gonsálvez <
> siglesias at igalia.com> wrote:
>
>> When creating a vtn_pointer for an OpVariable, the block_index and
>> offsets fields are null because there is not ssa to take the data
>> from.
>>
>> However, we can dereference that pointer when processing an
>> SpvOp*AccessChain opcodes through vtn_ssa_offset_pointer_dereference()
>> when the OpVariable when the StorageClass is Uniform or StorageBuffer.
>>
>> Inside vtn_ssa_offset_pointer_dereference() we have the code to
>> initialize block_index and offset if they are null, but it is called
>> after checking if the pointer has then non-null.
>>
>
> This seems fishy.  The code you're moving only triggers for
> OpPtrAccessChain.  In order to run into an issue, they would have to be
> doing an OpPtrAccessChain an an array of resources.  This shouldn't be
> allowed by the spec.  I'll have to look at the actual SPIR-V to be sure,
> but I think this is probably a CTS bug.
>
>
>
> For example, one of the tests failing is: dEQP-VK.spirv_assembly.
> instruction.compute.indexing.opptraccesschain_u32
>

Did a little looking at this test in particular and it's definitely bogus.


> A snippet of its SPIR-V is:
>
> [...]
> OpDecorate %_ptr_buffer_Input ArrayStride 65536
> [...]
> %Input = OpTypeStruct %_arr__arr_mat4v4float_uint_32_uint_32
>

This is a struct containing an array of arrays.  The struct is decorated
with Block which is reasonable


> %_ptr_buffer_Input = OpTypePointer StorageBuffer %Input
>

This is a pointer to that struct.  In the full SPIR-V, it's decorated with
an array stride which makes no sense whatsoever because you can't just jump
from one block to the next with a stride.  It's possible that the test
author intended to have the block contain an implicit array of structs but
if they wanted that then they should have done a struct of array of struct
of array of array of matrices.


> %dataInput = OpVariable %_ptr_buffer_Input StorageBuffer
> [...]
> %54 = OpPtrAccessChain %_ptr_buffer_float %dataInput %idx_1 %idx_0 %i0 %i1
> %i2 %i3
>
> %dataInput points to a struct of an AoA of matrices. However, according to
> SPV_KHR_variable_pointers [0]:
>
>    -
>
>    Each *OpPtrAccessChain* must have a *Base* whose type is decorated
>    with *ArrayStride*.
>
>
That is the rule that *should* be catching this but they got around it by
slapping a bogus ArrayStride decoration onto it.  I'm not really sure what
SPIR-V rule is supposed to catch this.  One of the design flaws of SPIR-V
is that we have valid usage rules based on decorations like you quoted
above but we have no way of saying that
%_arr__arr_mat4v4float_uint_32_uint_32 can't have an ArrayStride
decoration.  In fact, it can have such a decoration and might have to if
it's also embedded in an array somewhere.  I'll file SPIR-V and CTS bugs.
I really wish we had caught this before the test got merged...

--Jason


>
>    -
>
>
> So I think this is fine, or am I understanding it wrongly?
>
> Sam
>
> [0] https://www.khronos.org/registry/spir-v/extensions/
> KHR/SPV_KHR_variable_pointers.html
> <https://www.khronos.org/registry/spir-v/specs/1.2/SPIRV.html#OpPtrAccessChain>
>
>
> Reordering that code fixes crashes in:
>>
>>    dEQP-VK.spirv_assembly.instruction.*.indexing.*
>>
>> Signed-off-by: Samuel Iglesias Gonsálvez <siglesias at igalia.com>
>> ---
>>  src/compiler/spirv/vtn_variables.c | 29 +++++++++++++++--------------
>>  1 file changed, 15 insertions(+), 14 deletions(-)
>>
>> diff --git a/src/compiler/spirv/vtn_variables.c
>> b/src/compiler/spirv/vtn_variables.c
>> index 4f6acd2e07..baf1edde4c 100644
>> --- a/src/compiler/spirv/vtn_variables.c
>> +++ b/src/compiler/spirv/vtn_variables.c
>> @@ -146,20 +146,6 @@ vtn_ssa_offset_pointer_dereference(struct
>> vtn_builder *b,
>>     struct vtn_type *type = base->type;
>>
>>     unsigned idx = 0;
>> -   if (deref_chain->ptr_as_array) {
>> -      /* We need ptr_type for the stride */
>> -      assert(base->ptr_type);
>> -      /* This must be a pointer to an actual element somewhere */
>> -      assert(block_index && offset);
>> -      /* We need at least one element in the chain */
>> -      assert(deref_chain->length >= 1);
>> -
>> -      nir_ssa_def *elem_offset =
>> -         vtn_access_link_as_ssa(b, deref_chain->link[idx],
>> -                                base->ptr_type->stride);
>> -      offset = nir_iadd(&b->nb, offset, elem_offset);
>> -      idx++;
>> -   }
>>
>>     if (!block_index) {
>>        assert(base->var);
>> @@ -182,6 +168,21 @@ vtn_ssa_offset_pointer_dereference(struct
>> vtn_builder *b,
>>     }
>>     assert(offset);
>>
>> +   if (deref_chain->ptr_as_array) {
>> +      /* We need ptr_type for the stride */
>> +      assert(base->ptr_type);
>> +      /* This must be a pointer to an actual element somewhere */
>> +      assert(block_index && offset);
>> +      /* We need at least one element in the chain */
>> +      assert(deref_chain->length >= 1);
>> +
>> +      nir_ssa_def *elem_offset =
>> +         vtn_access_link_as_ssa(b, deref_chain->link[idx],
>> +                                base->ptr_type->stride);
>> +      offset = nir_iadd(&b->nb, offset, elem_offset);
>> +      idx++;
>> +   }
>> +
>>     for (; idx < deref_chain->length; idx++) {
>>        switch (glsl_get_base_type(type->type)) {
>>        case GLSL_TYPE_UINT:
>> --
>> 2.14.1
>>
>> _______________________________________________
>> mesa-dev mailing list
>> mesa-dev at lists.freedesktop.org
>> https://lists.freedesktop.org/mailman/listinfo/mesa-dev
>>
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/mesa-dev/attachments/20170911/2fd9ef81/attachment.html>


More information about the mesa-dev mailing list