Commit 60727de1 by Alexis Hetu Committed by Alexis Hétu

Detect out of bounds image pointers

When the out of bounds behavior is defined and any of the image coordinates is out of bounds, this cl manually pushes the pointer out of bounds in order to trigger the out of bounds behavior even if the resulting pointer would still be within memory bounds. Bug: b/150464740 Change-Id: I685973dfac440a8bca830810cf974819cfbc0f33 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/43950 Presubmit-Ready: Alexis Hétu <sugoi@google.com> Kokoro-Result: kokoro <noreply+kokoro@google.com> Tested-by: 's avatarAlexis Hétu <sugoi@google.com> Reviewed-by: 's avatarNicolas Capens <nicolascapens@google.com>
parent baa10d7b
...@@ -1211,7 +1211,7 @@ private: ...@@ -1211,7 +1211,7 @@ private:
void EmitImageSampleUnconditional(Array<SIMD::Float> &out, ImageInstruction instruction, InsnIterator insn, EmitState *state) const; void EmitImageSampleUnconditional(Array<SIMD::Float> &out, ImageInstruction instruction, InsnIterator insn, EmitState *state) const;
void GetImageDimensions(EmitState const *state, Type const &resultTy, Object::ID imageId, Object::ID lodId, Intermediate &dst) const; void GetImageDimensions(EmitState const *state, Type const &resultTy, Object::ID imageId, Object::ID lodId, Intermediate &dst) const;
SIMD::Pointer GetTexelAddress(EmitState const *state, SIMD::Pointer base, Operand const &coordinate, Type const &imageType, Pointer<Byte> descriptor, int texelSize, Object::ID sampleId, bool useStencilAspect) const; SIMD::Pointer GetTexelAddress(EmitState const *state, SIMD::Pointer base, Operand const &coordinate, Type const &imageType, Pointer<Byte> descriptor, int texelSize, Object::ID sampleId, bool useStencilAspect, OutOfBoundsBehavior outOfBoundsBehavior) const;
uint32_t GetConstScalarInt(Object::ID id) const; uint32_t GetConstScalarInt(Object::ID id) const;
void EvalSpecConstantOp(InsnIterator insn); void EvalSpecConstantOp(InsnIterator insn);
void EvalSpecConstantUnaryOp(InsnIterator insn); void EvalSpecConstantUnaryOp(InsnIterator insn);
......
...@@ -476,7 +476,7 @@ SpirvShader::EmitResult SpirvShader::EmitImageQuerySamples(InsnIterator insn, Em ...@@ -476,7 +476,7 @@ SpirvShader::EmitResult SpirvShader::EmitImageQuerySamples(InsnIterator insn, Em
return EmitResult::Continue; return EmitResult::Continue;
} }
SIMD::Pointer SpirvShader::GetTexelAddress(EmitState const *state, SIMD::Pointer ptr, Operand const &coordinate, Type const &imageType, Pointer<Byte> descriptor, int texelSize, Object::ID sampleId, bool useStencilAspect) const SIMD::Pointer SpirvShader::GetTexelAddress(EmitState const *state, SIMD::Pointer basePtr, Operand const &coordinate, Type const &imageType, Pointer<Byte> descriptor, int texelSize, Object::ID sampleId, bool useStencilAspect, OutOfBoundsBehavior outOfBoundsBehavior) const
{ {
auto routine = state->routine; auto routine = state->routine;
bool isArrayed = imageType.definition.word(5) != 0; bool isArrayed = imageType.definition.word(5) != 0;
...@@ -509,33 +509,69 @@ SIMD::Pointer SpirvShader::GetTexelAddress(EmitState const *state, SIMD::Pointer ...@@ -509,33 +509,69 @@ SIMD::Pointer SpirvShader::GetTexelAddress(EmitState const *state, SIMD::Pointer
? OFFSET(vk::StorageImageDescriptor, stencilSamplePitchBytes) ? OFFSET(vk::StorageImageDescriptor, stencilSamplePitchBytes)
: OFFSET(vk::StorageImageDescriptor, samplePitchBytes)))); : OFFSET(vk::StorageImageDescriptor, samplePitchBytes))));
ptr += u * SIMD::Int(texelSize); // If the out of bounds behavior is set to nullify, then out of bounds coordinates must be properly detected.
// Other out of bounds behaviors work properly without precise out of bounds coordinate detection.
bool nullifyOutOfBounds = (outOfBoundsBehavior == OutOfBoundsBehavior::Nullify);
SIMD::Int ptrOffset(0);
SIMD::Int oobMask(0);
if(nullifyOutOfBounds)
{
auto width = SIMD::Int(*Pointer<Int>(descriptor + OFFSET(vk::StorageImageDescriptor, extent.width)));
oobMask |= CmpLT(u, SIMD::Int(0)) | CmpNLT(u, width);
}
ptrOffset += u * SIMD::Int(texelSize);
if(dims > 1) if(dims > 1)
{ {
ptr += v * rowPitch; if(nullifyOutOfBounds)
{
auto height = SIMD::Int(*Pointer<Int>(descriptor + OFFSET(vk::StorageImageDescriptor, extent.height)));
oobMask |= CmpLT(v, SIMD::Int(0)) | CmpNLT(v, height);
}
ptrOffset += v * rowPitch;
} }
if((dims > 2) || isArrayed)
{
SIMD::Int w(0);
if(dims > 2) if(dims > 2)
{ {
ptr += coordinate.Int(2) * slicePitch; w += coordinate.Int(2);
} }
if(isArrayed) if(isArrayed)
{ {
ptr += coordinate.Int(dims) * slicePitch; w += coordinate.Int(dims);
}
if(nullifyOutOfBounds)
{
auto depth = SIMD::Int(*Pointer<Int>(descriptor + OFFSET(vk::StorageImageDescriptor, extent.depth)));
auto arrayLayers = SIMD::Int(*Pointer<Int>(descriptor + OFFSET(vk::StorageImageDescriptor, arrayLayers)));
oobMask |= CmpLT(w, SIMD::Int(0)) | CmpNLT(w, depth * arrayLayers);
}
ptrOffset += w * slicePitch;
} }
if(dim == spv::DimSubpassData) if(dim == spv::DimSubpassData)
{ {
// Multiview input attachment access is to the layer corresponding to the current view // Multiview input attachment access is to the layer corresponding to the current view
ptr += SIMD::Int(routine->viewID) * slicePitch; ptrOffset += SIMD::Int(routine->viewID) * slicePitch;
} }
if(sampleId.value()) if(sampleId.value())
{ {
Operand sample(this, state, sampleId); Operand sample(this, state, sampleId);
ptr += sample.Int(0) * samplePitch; ptrOffset += sample.Int(0) * samplePitch;
}
if(nullifyOutOfBounds)
{
// Because pointers can be 32b, using 0xFFFFFFFF would wrap around to about the same point,
// so use a smaller number
static constexpr int FORCE_OOB = 0x3FFFFFFF; // ~1 Gb, should be larger than any allocated image
// Push pointers out of bounds if they are oob in any dimension
ptrOffset += (oobMask & SIMD::Int(FORCE_OOB));
} }
return ptr; return basePtr + ptrOffset;
} }
SpirvShader::EmitResult SpirvShader::EmitImageRead(InsnIterator insn, EmitState *state) const SpirvShader::EmitResult SpirvShader::EmitImageRead(InsnIterator insn, EmitState *state) const
...@@ -593,14 +629,18 @@ SpirvShader::EmitResult SpirvShader::EmitImageRead(InsnIterator insn, EmitState ...@@ -593,14 +629,18 @@ SpirvShader::EmitResult SpirvShader::EmitImageRead(InsnIterator insn, EmitState
auto &dst = state->createIntermediate(insn.resultId(), resultType.componentCount); auto &dst = state->createIntermediate(insn.resultId(), resultType.componentCount);
auto texelSize = vk::Format(vkFormat).bytes();
auto basePtr = SIMD::Pointer(imageBase, imageSizeInBytes);
auto texelPtr = GetTexelAddress(state, basePtr, coordinate, imageType, binding, texelSize, sampleId, useStencilAspect);
// "The value returned by a read of an invalid texel is undefined, // "The value returned by a read of an invalid texel is undefined,
// unless that read operation is from a buffer resource and the robustBufferAccess feature is enabled." // unless that read operation is from a buffer resource and the robustBufferAccess feature is enabled."
// TODO: Don't always assume a buffer resource. // TODO: Don't always assume a buffer resource.
auto robustness = OutOfBoundsBehavior::RobustBufferAccess; //
// While we could be using OutOfBoundsBehavior::RobustBufferAccess for read operations from buffer resources,
// emulating the glsl function loadImage() requires that this function returns 0 when used with out of bounds
// coordinates, so we have to use OutOfBoundsBehavior::Nullify in that case.
auto robustness = OutOfBoundsBehavior::Nullify;
auto texelSize = vk::Format(vkFormat).bytes();
auto basePtr = SIMD::Pointer(imageBase, imageSizeInBytes);
auto texelPtr = GetTexelAddress(state, basePtr, coordinate, imageType, binding, texelSize, sampleId, useStencilAspect, robustness);
SIMD::Int packed[4]; SIMD::Int packed[4];
// Round up texel size: for formats smaller than 32 bits per texel, we will emit a bunch // Round up texel size: for formats smaller than 32 bits per texel, we will emit a bunch
...@@ -976,12 +1016,12 @@ SpirvShader::EmitResult SpirvShader::EmitImageWrite(InsnIterator insn, EmitState ...@@ -976,12 +1016,12 @@ SpirvShader::EmitResult SpirvShader::EmitImageWrite(InsnIterator insn, EmitState
break; break;
} }
auto basePtr = SIMD::Pointer(imageBase, imageSizeInBytes);
auto texelPtr = GetTexelAddress(state, basePtr, coordinate, imageType, binding, texelSize, 0, false);
// SPIR-V 1.4: "If the coordinates are outside the image, the memory location that is accessed is undefined." // SPIR-V 1.4: "If the coordinates are outside the image, the memory location that is accessed is undefined."
auto robustness = OutOfBoundsBehavior::UndefinedValue; auto robustness = OutOfBoundsBehavior::UndefinedValue;
auto basePtr = SIMD::Pointer(imageBase, imageSizeInBytes);
auto texelPtr = GetTexelAddress(state, basePtr, coordinate, imageType, binding, texelSize, 0, false, robustness);
for(auto i = 0u; i < numPackedElements; i++) for(auto i = 0u; i < numPackedElements; i++)
{ {
texelPtr.Store(packed[i], robustness, state->activeLaneMask()); texelPtr.Store(packed[i], robustness, state->activeLaneMask());
...@@ -1012,7 +1052,7 @@ SpirvShader::EmitResult SpirvShader::EmitImageTexelPointer(InsnIterator insn, Em ...@@ -1012,7 +1052,7 @@ SpirvShader::EmitResult SpirvShader::EmitImageTexelPointer(InsnIterator insn, Em
auto imageSizeInBytes = *Pointer<Int>(binding + OFFSET(vk::StorageImageDescriptor, sizeInBytes)); auto imageSizeInBytes = *Pointer<Int>(binding + OFFSET(vk::StorageImageDescriptor, sizeInBytes));
auto basePtr = SIMD::Pointer(imageBase, imageSizeInBytes); auto basePtr = SIMD::Pointer(imageBase, imageSizeInBytes);
auto ptr = GetTexelAddress(state, basePtr, coordinate, imageType, binding, sizeof(uint32_t), 0, false); auto ptr = GetTexelAddress(state, basePtr, coordinate, imageType, binding, sizeof(uint32_t), 0, false, OutOfBoundsBehavior::UndefinedValue);
state->createPointer(resultId, ptr); state->createPointer(resultId, ptr);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment