Skip to content

Commit 17c4025

Browse files
committed
Avoid undefined behavior on signed shifts
1 parent cb50bba commit 17c4025

1 file changed

Lines changed: 32 additions & 9 deletions

File tree

Source/astcenc_color_unquantize.cpp

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// SPDX-License-Identifier: Apache-2.0
22
// ----------------------------------------------------------------------------
3-
// Copyright 2011-2023 Arm Limited
3+
// Copyright 2011-2025 Arm Limited
44
//
55
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
66
// use this file except in compliance with the License. You may obtain a copy
@@ -40,6 +40,27 @@ static ASTCENC_SIMD_INLINE vint4 uncontract_color(
4040
return select(input, bc0, mask);
4141
}
4242

43+
/**
44+
* @brief Signed left shift that allows all bits to be shifted out.
45+
*
46+
* Doing this directly on a 32-bit signed type results in undefined behavior
47+
* for many possible shifts although works in practice for most compilers.
48+
*
49+
* @param val The original value.
50+
* @param shift The left shift amount.
51+
*
52+
* @return The shifted value.
53+
*/
54+
static ASTCENC_SIMD_INLINE int32_t safe_signed_lsh(int32_t val, int shift)
55+
{
56+
// Future: When we support C++20 can swap memcpy for std::bitcast
57+
uint32_t uval;
58+
std::memcpy(&uval, &val, sizeof(uint32_t));
59+
uval <<= shift;
60+
std::memcpy(&val, &uval, sizeof(uint32_t));
61+
return val;
62+
}
63+
4364
void rgba_delta_unpack(
4465
vint4 input0,
4566
vint4 input1,
@@ -597,21 +618,23 @@ static void hdr_rgb_unpack(
597618
int32_t d0x = d0;
598619
int32_t d1x = d1;
599620
int sx_shamt = 32 - dbits;
600-
d0x <<= sx_shamt;
621+
622+
d0x = safe_signed_lsh(d0x, sx_shamt);
601623
d0x >>= sx_shamt;
602-
d1x <<= sx_shamt;
624+
d1x = safe_signed_lsh(d1x, sx_shamt);
603625
d1x >>= sx_shamt;
626+
604627
d0 = d0x;
605628
d1 = d1x;
606629

607630
// expand all values to 12 bits, with left-shift as needed.
608631
int val_shamt = (modeval >> 1) ^ 3;
609-
a <<= val_shamt;
610-
b0 <<= val_shamt;
611-
b1 <<= val_shamt;
612-
c <<= val_shamt;
613-
d0 <<= val_shamt;
614-
d1 <<= val_shamt;
632+
a = safe_signed_lsh(a, val_shamt);
633+
b0 = safe_signed_lsh(b0, val_shamt);
634+
b1 = safe_signed_lsh(b1, val_shamt);
635+
c = safe_signed_lsh(c, val_shamt);
636+
d0 = safe_signed_lsh(d0, val_shamt);
637+
d1 = safe_signed_lsh(d1, val_shamt);
615638

616639
// then compute the actual color values.
617640
int red1 = a;

0 commit comments

Comments
 (0)