From 905b8244e7756d8657c3a3ef97693af00f9e38bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Aedo?= Date: Thu, 11 Nov 2021 12:57:57 -0300 Subject: [PATCH] Clamp vector element access to vector size. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In cases where we know the size of the vector and the index at compile time, we can check if it's accessing in bounds and rely in undefined behavior otherwise. Signed-off-by: Sebastián Aedo --- ...t-of-bounds-access-opspecconstant.asm.frag | 8 ++++ .../asm/frag/out-of-bounds-access.asm.frag | 8 ++++ ...t-of-bounds-access-opspecconstant.asm.frag | 15 ++++++ .../asm/frag/out-of-bounds-access.asm.frag | 14 ++++++ ...t-of-bounds-access-opspecconstant.asm.frag | 42 +++++++++++++++++ .../asm/frag/out-of-bounds-access.asm.frag | 47 +++++++++++++++++++ spirv_glsl.cpp | 27 +++++++---- 7 files changed, 151 insertions(+), 10 deletions(-) create mode 100644 reference/opt/shaders/asm/frag/out-of-bounds-access-opspecconstant.asm.frag create mode 100644 reference/opt/shaders/asm/frag/out-of-bounds-access.asm.frag create mode 100644 reference/shaders/asm/frag/out-of-bounds-access-opspecconstant.asm.frag create mode 100644 reference/shaders/asm/frag/out-of-bounds-access.asm.frag create mode 100644 shaders/asm/frag/out-of-bounds-access-opspecconstant.asm.frag create mode 100644 shaders/asm/frag/out-of-bounds-access.asm.frag diff --git a/reference/opt/shaders/asm/frag/out-of-bounds-access-opspecconstant.asm.frag b/reference/opt/shaders/asm/frag/out-of-bounds-access-opspecconstant.asm.frag new file mode 100644 index 00000000..4734c89c --- /dev/null +++ b/reference/opt/shaders/asm/frag/out-of-bounds-access-opspecconstant.asm.frag @@ -0,0 +1,8 @@ +#version 320 es +precision mediump float; +precision highp int; + +void main() +{ +} + diff --git a/reference/opt/shaders/asm/frag/out-of-bounds-access.asm.frag b/reference/opt/shaders/asm/frag/out-of-bounds-access.asm.frag new file mode 100644 index 00000000..4734c89c --- /dev/null +++ b/reference/opt/shaders/asm/frag/out-of-bounds-access.asm.frag @@ -0,0 +1,8 @@ +#version 320 es +precision mediump float; +precision highp int; + +void main() +{ +} + diff --git a/reference/shaders/asm/frag/out-of-bounds-access-opspecconstant.asm.frag b/reference/shaders/asm/frag/out-of-bounds-access-opspecconstant.asm.frag new file mode 100644 index 00000000..eddb3829 --- /dev/null +++ b/reference/shaders/asm/frag/out-of-bounds-access-opspecconstant.asm.frag @@ -0,0 +1,15 @@ +#version 320 es +precision mediump float; +precision highp int; + +const uint _15 = 3u; + +void main() +{ + vec3 v = vec3(0.0); + if (false) + { + v[0] = 99.0; + } +} + diff --git a/reference/shaders/asm/frag/out-of-bounds-access.asm.frag b/reference/shaders/asm/frag/out-of-bounds-access.asm.frag new file mode 100644 index 00000000..080283d4 --- /dev/null +++ b/reference/shaders/asm/frag/out-of-bounds-access.asm.frag @@ -0,0 +1,14 @@ +#version 320 es +precision mediump float; +precision highp int; + +void main() +{ + vec3 v = vec3(0.0); + if (false) + { + v.x = 99.0; + v.x = 88.0; + } +} + diff --git a/shaders/asm/frag/out-of-bounds-access-opspecconstant.asm.frag b/shaders/asm/frag/out-of-bounds-access-opspecconstant.asm.frag new file mode 100644 index 00000000..628a9f5b --- /dev/null +++ b/shaders/asm/frag/out-of-bounds-access-opspecconstant.asm.frag @@ -0,0 +1,42 @@ +; SPIR-V +; Version: 1.0 +; Generator: Google Shaderc over Glslang; 10 +; Bound: 21 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpSource ESSL 320 + OpSourceExtension "GL_GOOGLE_cpp_style_line_directive" + OpSourceExtension "GL_GOOGLE_include_directive" + OpName %main "main" + OpName %v "v" + OpDecorate %v RelaxedPrecision + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v3float = OpTypeVector %float 3 +%_ptr_Function_v3float = OpTypePointer Function %v3float + %float_0 = OpConstant %float 0 + %11 = OpConstantComposite %v3float %float_0 %float_0 %float_0 + %bool = OpTypeBool + %false = OpConstantFalse %bool + %float_99 = OpConstant %float 99 + %uint = OpTypeInt 32 0 +%uint_spec_3 = OpSpecConstant %uint 3 +%_ptr_Function_float = OpTypePointer Function %float + %main = OpFunction %void None %3 + %5 = OpLabel + %v = OpVariable %_ptr_Function_v3float Function + OpStore %v %11 + OpSelectionMerge %15 None + OpBranchConditional %false %14 %15 + %14 = OpLabel + %20 = OpAccessChain %_ptr_Function_float %v %uint_spec_3 + OpStore %20 %float_99 + OpBranch %15 + %15 = OpLabel + OpReturn + OpFunctionEnd diff --git a/shaders/asm/frag/out-of-bounds-access.asm.frag b/shaders/asm/frag/out-of-bounds-access.asm.frag new file mode 100644 index 00000000..542b74b2 --- /dev/null +++ b/shaders/asm/frag/out-of-bounds-access.asm.frag @@ -0,0 +1,47 @@ +; SPIR-V +; Version: 1.0 +; Generator: Google Shaderc over Glslang; 10 +; Bound: 21 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpSource ESSL 320 + OpSourceExtension "GL_GOOGLE_cpp_style_line_directive" + OpSourceExtension "GL_GOOGLE_include_directive" + OpName %main "main" + OpName %v "v" + OpDecorate %v RelaxedPrecision + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v3float = OpTypeVector %float 3 +%_ptr_Function_v3float = OpTypePointer Function %v3float + %float_0 = OpConstant %float 0 + %11 = OpConstantComposite %v3float %float_0 %float_0 %float_0 + %bool = OpTypeBool + %false = OpConstantFalse %bool + %float_99 = OpConstant %float 99 + %float_88 = OpConstant %float 88 + %uint = OpTypeInt 32 0 + %uint_3 = OpConstant %uint 3 + %sint = OpTypeInt 32 1 + %sint_3 = OpConstant %sint -1 +%_ptr_Function_float = OpTypePointer Function %float + %main = OpFunction %void None %3 + %5 = OpLabel + %v = OpVariable %_ptr_Function_v3float Function + OpStore %v %11 + OpSelectionMerge %15 None + OpBranchConditional %false %14 %15 + %14 = OpLabel + %20 = OpAccessChain %_ptr_Function_float %v %uint_3 + OpStore %20 %float_99 + %99 = OpAccessChain %_ptr_Function_float %v %sint_3 + OpStore %99 %float_88 + OpBranch %15 + %15 = OpLabel + OpReturn + OpFunctionEnd diff --git a/spirv_glsl.cpp b/spirv_glsl.cpp index cdc1c6b6..f06ed2c0 100644 --- a/spirv_glsl.cpp +++ b/spirv_glsl.cpp @@ -8894,30 +8894,37 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice is_packed); } - if (is_literal && !is_packed && !row_major_matrix_needs_conversion) + if (is_literal) { - expr += "."; - expr += index_to_swizzle(index); + bool out_of_bounds = (index >= type->vecsize); + + if (!is_packed && !row_major_matrix_needs_conversion) + { + expr += "."; + expr += index_to_swizzle(out_of_bounds ? 0 : index); + } + else + { + // For packed vectors, we can only access them as an array, not by swizzle. + expr += join("[", out_of_bounds ? 0 : index, "]"); + } } else if (ir.ids[index].get_type() == TypeConstant && !is_packed && !row_major_matrix_needs_conversion) { auto &c = get(index); + bool out_of_bounds = (c.scalar() >= type->vecsize); + if (c.specialization) { // If the index is a spec constant, we cannot turn extract into a swizzle. - expr += join("[", to_expression(index), "]"); + expr += join("[", out_of_bounds ? "0" : to_expression(index), "]"); } else { expr += "."; - expr += index_to_swizzle(c.scalar()); + expr += index_to_swizzle(out_of_bounds ? 0 : c.scalar()); } } - else if (is_literal) - { - // For packed vectors, we can only access them as an array, not by swizzle. - expr += join("[", index, "]"); - } else { expr += "[";