Make signed guf_wrapping_mul more general

Don't fail on mod == 0 (in weird cases where the given UNSIGNED_TYPE_MAX == SIGNED_TYPE_MAX)
but
res = mod > 0 ? (1u * res % mod) : res;
This commit is contained in:
jun 2025-05-15 09:21:30 +02:00
parent 466982ffcb
commit 9b64b22806
2 changed files with 15 additions and 21 deletions

View File

@ -68,6 +68,7 @@
cf. https://stackoverflow.com/questions/27001604/32-bit-unsigned-multiply-on-64-bit-causing-undefined-behavior (last-retrieved 2025-05-15) cf. https://stackoverflow.com/questions/27001604/32-bit-unsigned-multiply-on-64-bit-causing-undefined-behavior (last-retrieved 2025-05-15)
*/ */
#if defined(GUF_MATH_CKDINT_IMPL_STATIC) #if defined(GUF_MATH_CKDINT_IMPL_STATIC)
#define GUF_MATH_CKDINT_KWRDS static inline #define GUF_MATH_CKDINT_KWRDS static inline
#else #else
@ -808,9 +809,8 @@ GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_int(int a, int b, int
case GUF_MATH_CKD_OVERFLOW_NEG: { case GUF_MATH_CKD_OVERFLOW_NEG: {
unsigned res = 1u * (unsigned)a * (unsigned)b; unsigned res = 1u * (unsigned)a * (unsigned)b;
if (res > INT_MAX) { // This is the fix for implementation defined conversion from unsigned to signed. if (res > INT_MAX) { // This is the fix for implementation defined conversion from unsigned to signed.
const unsigned mod = (1u * (unsigned)INT_MAX + 1u); const unsigned mod = (1u + (unsigned)INT_MAX);
GUF_ASSERT(mod > 0 && mod > INT_MAX); res = mod > 0 ? (1u * res % mod) : res;
res = 1u * res % mod;
*result = INT_MIN + (int)res; *result = INT_MIN + (int)res;
} else { } else {
*result = (int)res; *result = (int)res;
@ -940,9 +940,8 @@ GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_i8(int8_t a, int8_t b
case GUF_MATH_CKD_OVERFLOW_NEG: { case GUF_MATH_CKD_OVERFLOW_NEG: {
uint8_t res = 1u * (uint8_t)a * (uint8_t)b; uint8_t res = 1u * (uint8_t)a * (uint8_t)b;
if (res > INT8_MAX) { // This is the fix for implementation defined conversion from unsigned to signed. if (res > INT8_MAX) { // This is the fix for implementation defined conversion from unsigned to signed.
const uint8_t mod = (1u * (uint8_t)INT8_MAX + 1u); const uint8_t mod = (1u + (uint8_t)INT8_MAX);
GUF_ASSERT(mod > 0 && mod > INT8_MAX); res = mod > 0 ? (1u * res % mod) : res;
res = 1u * res % mod;
*result = INT8_MIN + (int8_t)res; *result = INT8_MIN + (int8_t)res;
} else { } else {
*result = (int8_t)res; *result = (int8_t)res;
@ -1072,9 +1071,8 @@ GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_i16(int16_t a, int16_
case GUF_MATH_CKD_OVERFLOW_NEG: { case GUF_MATH_CKD_OVERFLOW_NEG: {
uint16_t res = 1u * (uint16_t)a * (uint16_t)b; uint16_t res = 1u * (uint16_t)a * (uint16_t)b;
if (res > INT16_MAX) { // This is the fix for implementation defined conversion from unsigned to signed. if (res > INT16_MAX) { // This is the fix for implementation defined conversion from unsigned to signed.
const uint16_t mod = (1u * (uint16_t)INT16_MAX + 1u); const uint16_t mod = (1u + (uint16_t)INT16_MAX);
GUF_ASSERT(mod > 0 && mod > INT16_MAX); res = mod > 0 ? (1u * res % mod) : res;
res = 1u * res % mod;
*result = INT16_MIN + (int16_t)res; *result = INT16_MIN + (int16_t)res;
} else { } else {
*result = (int16_t)res; *result = (int16_t)res;
@ -1204,9 +1202,8 @@ GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_i32(int32_t a, int32_
case GUF_MATH_CKD_OVERFLOW_NEG: { case GUF_MATH_CKD_OVERFLOW_NEG: {
uint32_t res = 1u * (uint32_t)a * (uint32_t)b; uint32_t res = 1u * (uint32_t)a * (uint32_t)b;
if (res > INT32_MAX) { // This is the fix for implementation defined conversion from unsigned to signed. if (res > INT32_MAX) { // This is the fix for implementation defined conversion from unsigned to signed.
const uint32_t mod = (1u * (uint32_t)INT32_MAX + 1u); const uint32_t mod = (1u + (uint32_t)INT32_MAX);
GUF_ASSERT(mod > 0 && mod > INT32_MAX); res = mod > 0 ? (1u * res % mod) : res;
res = 1u * res % mod;
*result = INT32_MIN + (int32_t)res; *result = INT32_MIN + (int32_t)res;
} else { } else {
*result = (int32_t)res; *result = (int32_t)res;
@ -1336,9 +1333,8 @@ GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_i64(int64_t a, int64_
case GUF_MATH_CKD_OVERFLOW_NEG: { case GUF_MATH_CKD_OVERFLOW_NEG: {
uint64_t res = 1u * (uint64_t)a * (uint64_t)b; uint64_t res = 1u * (uint64_t)a * (uint64_t)b;
if (res > INT64_MAX) { // This is the fix for implementation defined conversion from unsigned to signed. if (res > INT64_MAX) { // This is the fix for implementation defined conversion from unsigned to signed.
const uint64_t mod = (1u * (uint64_t)INT64_MAX + 1u); const uint64_t mod = (1u + (uint64_t)INT64_MAX);
GUF_ASSERT(mod > 0 && mod > INT64_MAX); res = mod > 0 ? (1u * res % mod) : res;
res = 1u * res % mod;
*result = INT64_MIN + (int64_t)res; *result = INT64_MIN + (int64_t)res;
} else { } else {
*result = (int64_t)res; *result = (int64_t)res;
@ -1468,9 +1464,8 @@ GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_ptrdiff_t(ptrdiff_t a
case GUF_MATH_CKD_OVERFLOW_NEG: { case GUF_MATH_CKD_OVERFLOW_NEG: {
size_t res = 1u * (size_t)a * (size_t)b; size_t res = 1u * (size_t)a * (size_t)b;
if (res > PTRDIFF_MAX) { // This is the fix for implementation defined conversion from unsigned to signed. if (res > PTRDIFF_MAX) { // This is the fix for implementation defined conversion from unsigned to signed.
const size_t mod = (1u * (size_t)PTRDIFF_MAX + 1u); const size_t mod = (1u + (size_t)PTRDIFF_MAX);
GUF_ASSERT(mod > 0 && mod > PTRDIFF_MAX); res = mod > 0 ? (1u * res % mod) : res;
res = 1u * res % mod;
*result = PTRDIFF_MIN + (ptrdiff_t)res; *result = PTRDIFF_MIN + (ptrdiff_t)res;
} else { } else {
*result = (ptrdiff_t)res; *result = (ptrdiff_t)res;

View File

@ -232,9 +232,8 @@ def generate_ckdint_functions(int_types: list, uint_types: list) -> Tuple[str, s
case GUF_MATH_CKD_OVERFLOW_NEG: {{ case GUF_MATH_CKD_OVERFLOW_NEG: {{
{uint_type} res = 1u * ({uint_type})a * ({uint_type})b; {uint_type} res = 1u * ({uint_type})a * ({uint_type})b;
if (res > {int_max}) {{ // This is the fix for implementation defined conversion from unsigned to signed. if (res > {int_max}) {{ // This is the fix for implementation defined conversion from unsigned to signed.
const {uint_type} mod = (1u * ({uint_type}){int_max} + 1u); const {uint_type} mod = (1u + ({uint_type}){int_max});
GUF_ASSERT(mod > 0 && mod > {int_max}); res = mod > 0 ? (1u * res % mod) : res;
res = 1u * res % mod;
*result = {int_min} + ({type})res; *result = {int_min} + ({type})res;
}} else {{ }} else {{
*result = ({type})res; *result = ({type})res;