tint: Fix C++ UB when shifting abstract 0 left by >= 64
In WGSL, we can shift left abstracts by >= 64, as long as the result is representable in the data type we choose for it. When shifting 0, we can shift by any positive u32 value (result is always 0), but in C++, it's UB to shift by more than the bit width of the data type, so we need to handle this. This bug was caught by ClusterFuzz. Bug: chromium:1372963 Change-Id: I638ca190b93538908ca6472f3735627ea8531c5a Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/106266 Reviewed-by: David Neto <dneto@google.com> Commit-Queue: Antonio Maiorano <amaiorano@google.com> Reviewed-by: Dan Sinclair <dsinclair@chromium.org> Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
parent
e4d608a837
commit
b6e1bc7d5d
|
@ -1474,6 +1474,10 @@ ConstEval::Result ConstEval::OpShiftLeft(const sem::Type* ty,
|
|||
AddError(OverflowErrorMessage(e1, "<<", e2), source);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// It's UB in C++ to shift by greater or equal to the bit width (even if the lhs
|
||||
// is 0), so we make sure to avoid this by setting the shift value to 0.
|
||||
e2 = 0;
|
||||
}
|
||||
} else {
|
||||
if (static_cast<size_t>(e2) >= bit_width) {
|
||||
|
|
|
@ -598,7 +598,7 @@ std::vector<Case> ShiftLeftCases() {
|
|||
// Shift type is u32 for non-abstract
|
||||
using ST = std::conditional_t<IsAbstract<T>, T, u32>;
|
||||
using B = BitValues<T>;
|
||||
return {
|
||||
auto r = std::vector<Case>{
|
||||
C(T{0b1010}, ST{0}, T{0b0000'0000'1010}), //
|
||||
C(T{0b1010}, ST{1}, T{0b0000'0001'0100}), //
|
||||
C(T{0b1010}, ST{2}, T{0b0000'0010'1000}), //
|
||||
|
@ -626,6 +626,25 @@ std::vector<Case> ShiftLeftCases() {
|
|||
Vec(ST{6}, ST{7}, ST{8}), //
|
||||
Vec(T{0b0010'1000'0000}, T{0b0101'0000'0000}, T{0b1010'0000'0000})), //
|
||||
};
|
||||
|
||||
// Only abstract 0 can be shifted left as much as we like. For concrete 0 (and any number), it
|
||||
// cannot be shifted equal or more than the number of bits of the lhs (see
|
||||
// ResolverConstEvalShiftLeftConcreteGeqBitWidthError)
|
||||
ConcatIntoIf<IsAbstract<T>>( //
|
||||
r, std::vector<Case>{
|
||||
C(T{0}, ST{64}, T{0}),
|
||||
C(T{0}, ST{65}, T{0}),
|
||||
C(T{0}, ST{65}, T{0}),
|
||||
C(T{0}, ST{10000}, T{0}),
|
||||
C(T{0}, T::Highest(), T{0}),
|
||||
C(Negate(T{0}), ST{64}, Negate(T{0})),
|
||||
C(Negate(T{0}), ST{65}, Negate(T{0})),
|
||||
C(Negate(T{0}), ST{65}, Negate(T{0})),
|
||||
C(Negate(T{0}), ST{10000}, Negate(T{0})),
|
||||
C(Negate(T{0}), T::Highest(), Negate(T{0})),
|
||||
});
|
||||
|
||||
return r;
|
||||
}
|
||||
INSTANTIATE_TEST_SUITE_P(ShiftLeft,
|
||||
ResolverConstEvalBinaryOpTest,
|
||||
|
@ -851,14 +870,36 @@ TEST_P(ResolverConstEvalShiftLeftConcreteGeqBitWidthError, Test) {
|
|||
INSTANTIATE_TEST_SUITE_P(Test,
|
||||
ResolverConstEvalShiftLeftConcreteGeqBitWidthError,
|
||||
testing::Values( //
|
||||
std::make_tuple(Val(0_u), Val(32_u)), //
|
||||
std::make_tuple(Val(0_u), Val(33_u)), //
|
||||
std::make_tuple(Val(0_u), Val(34_u)), //
|
||||
std::make_tuple(Val(0_u), Val(10000_u)), //
|
||||
std::make_tuple(Val(0_u), Val(u32::Highest())), //
|
||||
std::make_tuple(Val(0_i), Val(32_u)), //
|
||||
std::make_tuple(Val(0_i), Val(33_u)), //
|
||||
std::make_tuple(Val(0_i), Val(34_u)), //
|
||||
std::make_tuple(Val(0_i), Val(10000_u)), //
|
||||
std::make_tuple(Val(0_i), Val(u32::Highest())), //
|
||||
std::make_tuple(Val(Negate(0_u)), Val(32_u)), //
|
||||
std::make_tuple(Val(Negate(0_u)), Val(33_u)), //
|
||||
std::make_tuple(Val(Negate(0_u)), Val(34_u)), //
|
||||
std::make_tuple(Val(Negate(0_u)), Val(10000_u)), //
|
||||
std::make_tuple(Val(Negate(0_u)), Val(u32::Highest())), //
|
||||
std::make_tuple(Val(Negate(0_i)), Val(32_u)), //
|
||||
std::make_tuple(Val(Negate(0_i)), Val(33_u)), //
|
||||
std::make_tuple(Val(Negate(0_i)), Val(34_u)), //
|
||||
std::make_tuple(Val(Negate(0_i)), Val(10000_u)), //
|
||||
std::make_tuple(Val(Negate(0_i)), Val(u32::Highest())), //
|
||||
std::make_tuple(Val(1_i), Val(32_u)), //
|
||||
std::make_tuple(Val(1_i), Val(33_u)), //
|
||||
std::make_tuple(Val(1_i), Val(34_u)), //
|
||||
std::make_tuple(Val(1_i), Val(99999999_u)), //
|
||||
std::make_tuple(Val(1_i), Val(10000_u)), //
|
||||
std::make_tuple(Val(1_i), Val(u32::Highest())), //
|
||||
std::make_tuple(Val(1_u), Val(32_u)), //
|
||||
std::make_tuple(Val(1_u), Val(33_u)), //
|
||||
std::make_tuple(Val(1_u), Val(34_u)), //
|
||||
std::make_tuple(Val(1_u), Val(99999999_u)) //
|
||||
std::make_tuple(Val(1_u), Val(10000_u)), //
|
||||
std::make_tuple(Val(1_u), Val(u32::Highest())) //
|
||||
));
|
||||
|
||||
// AInt left shift results in sign change error
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
fn g() -> vec4<i32> {
|
||||
return vec4(-0) << vec4(2147483649);
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn main() {
|
||||
g();
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
int4 g() {
|
||||
return (0).xxxx;
|
||||
}
|
||||
|
||||
void main() {
|
||||
g();
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
int4 g() {
|
||||
return (0).xxxx;
|
||||
}
|
||||
|
||||
void main() {
|
||||
g();
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
#version 310 es
|
||||
precision mediump float;
|
||||
|
||||
ivec4 g() {
|
||||
return ivec4(0);
|
||||
}
|
||||
|
||||
void tint_symbol() {
|
||||
g();
|
||||
}
|
||||
|
||||
void main() {
|
||||
tint_symbol();
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
#include <metal_stdlib>
|
||||
|
||||
using namespace metal;
|
||||
int4 g() {
|
||||
return int4(0);
|
||||
}
|
||||
|
||||
fragment void tint_symbol() {
|
||||
g();
|
||||
return;
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
; SPIR-V
|
||||
; Version: 1.3
|
||||
; Generator: Google Tint Compiler; 0
|
||||
; Bound: 12
|
||||
; Schema: 0
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpName %g "g"
|
||||
OpName %main "main"
|
||||
%int = OpTypeInt 32 1
|
||||
%v4int = OpTypeVector %int 4
|
||||
%1 = OpTypeFunction %v4int
|
||||
%6 = OpConstantNull %v4int
|
||||
%void = OpTypeVoid
|
||||
%7 = OpTypeFunction %void
|
||||
%g = OpFunction %v4int None %1
|
||||
%5 = OpLabel
|
||||
OpReturnValue %6
|
||||
OpFunctionEnd
|
||||
%main = OpFunction %void None %7
|
||||
%10 = OpLabel
|
||||
%11 = OpFunctionCall %v4int %g
|
||||
OpReturn
|
||||
OpFunctionEnd
|
|
@ -0,0 +1,8 @@
|
|||
fn g() -> vec4<i32> {
|
||||
return (vec4(0) << vec4(2147483649));
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn main() {
|
||||
g();
|
||||
}
|
Loading…
Reference in New Issue