Skip to content

Commit 4f3d212

Browse files
committed
S_uv_mul_overflow in inline.h: Add casts to make multiplications done in UV
If C compiler doesn't know __builtin_mul_overflow, S_uv_mul_overflow will be implemented with fallback "long multiplication" algorithm, but it had a bug that elemental multiplications were done in unsigned long precision instead of UV precision. It will lead wrong result when unsigned long is narrower than UV (for example -Duse64bitint on 32-bit platform).
1 parent f288bce commit 4f3d212

File tree

1 file changed

+4
-2
lines changed

1 file changed

+4
-2
lines changed

inline.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3546,6 +3546,8 @@ S_uv_mul_overflow (UV auv, UV buv, UV *const result)
35463546
const UV botmask = ~topmask;
35473547

35483548
# if UVSIZE > LONGSIZE && UVSIZE <= 2 * LONGSIZE
3549+
/* If UV is double-word integer, declare these variables as single-word
3550+
integers to help compiler to avoid double-word multiplication. */
35493551
unsigned long alow, ahigh, blow, bhigh;
35503552
# else
35513553
UV alow, ahigh, blow, bhigh;
@@ -3567,7 +3569,7 @@ S_uv_mul_overflow (UV auv, UV buv, UV *const result)
35673569
/* One operand is large, 1 small */
35683570
/* Either ahigh or bhigh is zero here, so the addition below
35693571
can't overflow. */
3570-
product_middle = ahigh * blow + alow * bhigh;
3572+
product_middle = (UV)ahigh * blow + (UV)alow * bhigh;
35713573
if (product_middle & topmask)
35723574
return true;
35733575
/* OK, product_middle won't lose bits when we shift it. */
@@ -3576,7 +3578,7 @@ S_uv_mul_overflow (UV auv, UV buv, UV *const result)
35763578
/* else: eg 32 bit is at most 0xFFFF * 0xFFFF == 0xFFFE0001
35773579
so the unsigned multiply cannot overflow. */
35783580

3579-
UV product_low = alow * blow;
3581+
UV product_low = (UV)alow * blow;
35803582
return S_uv_add_overflow(product_middle, product_low, result);
35813583
}
35823584
# endif

0 commit comments

Comments
 (0)