nir: Fix undefined behavior due to signed integer multiplication overflows
authorTony Wasserka <tony.wasserka@gmx.de>
Wed, 9 Sep 2020 10:22:44 +0000 (12:22 +0200)
committerMarge Bot <eric+marge@anholt.net>
Wed, 7 Oct 2020 19:50:01 +0000 (19:50 +0000)
Notably this happened when applying constant folding on the intermediate
computations generated from nir_lower_idiv.

Reviewed-by: Rhys Perry <pendingchaos02@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6728>

src/compiler/nir/nir_opcodes.py

index 27b09fa..8226be0 100644 (file)
@@ -625,7 +625,10 @@ if (nir_is_rounding_mode_rtz(execution_mode, bit_size)) {
 }
 """)
 # low 32-bits of signed/unsigned integer multiply
-binop("imul", tint, _2src_commutative + associative, "src0 * src1")
+binop("imul", tint, _2src_commutative + associative, """
+   /* Use 64-bit multiplies to prevent overflow of signed arithmetic */
+   dst = (uint64_t)src0 * (uint64_t)src1;
+""")
 
 # Generate 64 bit result from 2 32 bits quantity
 binop_convert("imul_2x32_64", tint64, tint32, _2src_commutative,
@@ -656,7 +659,9 @@ if (bit_size == 64) {
    ubm_mul_u32arr(prod_u32, src0_u32, src1_u32);
    dst = (uint64_t)prod_u32[2] | ((uint64_t)prod_u32[3] << 32);
 } else {
-   dst = ((int64_t)src0 * (int64_t)src1) >> bit_size;
+   /* First, sign-extend to 64-bit, then convert to unsigned to prevent
+    * potential overflow of signed multiply */
+   dst = ((uint64_t)(int64_t)src0 * (uint64_t)(int64_t)src1) >> bit_size;
 }
 """)