DirectXShaderCompiler icon indicating copy to clipboard operation
DirectXShaderCompiler copied to clipboard

[SPIR-V] Conversion from `CommittedRayT` to `OpRayQueryGetIntersectionTKHR` can introduce UB

Open Vecvec opened this issue 1 month ago • 2 comments

Description query.CommittedRayT() is defined to be initialized to RayDesc::TMax, however, DXC converts this call directly to OpRayQueryGetIntersectionTKHR with an intersection type of RayQueryCommittedIntersectionKHR about which the extension specification states

If Intersection is RayQueryCommittedIntersectionKHR, behavior is undefined if there is no current committed intersection

In a case such as

RaytracingAccelerationStructure g_AS;
[numthreads(1, 1, 1)]
void CSMain()
{
    RayQuery<RAY_FLAG_NONE> query;
    RayDesc desc = (RayDesc)0;
    query.TraceRayInline(g_AS, 0, 0, desc);
    float unused = query.CommittedRayT();
}

this will always be undefined behavior in spirv, when what is returned should be TMax (zero in this case).

This could be a problem in the spirv specification, because the Vulkan spec in one case assumes that this is defined too. Alternatively, I could have missed something somewhere that makes this defined (but I can't find any in the Vulkan environment for spirv or in the extension spec itself).

Steps to Reproduce See https://godbolt.org/z/xGxb8GPf8

Actual Behavior

               OpRayQueryInitializeKHR %18 %19 %uint_0 %uint_0 %15 %16 %15 %16
         %20 = OpRayQueryGetIntersectionTKHR %float %18 %uint_1

is outputted, which according to the spirv specification has undefined behavior if hit.

Environment

  • DXC version libdxcompiler.so: 1.9(dev;1-9efbb6c3); libdxil.so: 1.9 (version from godbolt)
  • Host Operating System N/A

Vecvec avatar Oct 31 '25 00:10 Vecvec

I think you are right. We should be checking OpRayQueryGetIntersectionTypeKHR. It if returns RayQueryCommittedIntersectionNoneKHR, then return the default value RayDesc::TMax. Otherwise get the value from OpRayQueryGetIntersectionTKHR.

s-perron avatar Oct 31 '25 14:10 s-perron

This is much harder than I thought. The problem is that the TMax value is not available when expanding It is in the ray descriptor, but there is no SPIR-V function to get TMax from a ray query object to be able to return it as I said above. This will turn into a big change.

We may not get to this in DXC. In the mean time, I suggest making sure that you check the commit status before calling CommittedRayT.

s-perron avatar Nov 05 '25 16:11 s-perron