Fix overflow in guf_rand32range_i32 and guf_randrange_i64

This commit is contained in:
jun 2025-02-15 18:04:53 +01:00
parent 500fd47986
commit f911933588
3 changed files with 12 additions and 6 deletions

View File

@ -62,4 +62,10 @@ static inline int32_t guf_abs_i32(int32_t x) {if (x >= 0) {return x;}
static inline int64_t guf_abs_i64(int64_t x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(x > INT64_MIN); return -x;}
static inline ptrdiff_t guf_abs_ptrdiff(ptrdiff_t x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(x > PTRDIFF_MIN); return -x;}
static inline uint32_t guf_uabs_i32(int32_t x) {if (x >= 0) {return x;} else if (x == INT32_MIN) {return (uint32_t)INT32_MAX + 1;} else {return -x;}}
static inline uint64_t guf_uabs_i64(int64_t x) {if (x >= 0) {return x;} else if (x == INT64_MIN) {return (uint64_t)INT64_MAX + 1;} else {return -x;}}
static inline uint32_t guf_absdiff_i32(int32_t a, int32_t b) {return a > b ? (uint32_t)a - (uint32_t)b : (uint32_t)b - (uint32_t)a;}
static inline uint64_t guf_absdiff_i64(int64_t a, int64_t b) {return a > b ? (uint64_t)a - (uint64_t)b : (uint64_t)b - (uint64_t)a;}
#endif

View File

@ -223,7 +223,7 @@ GUF_FN_KEYWORDS int64_t guf_randrange_i64(guf_randstate *state, int64_t min, int
const unsigned rand_max_shift = 1;
const uint64_t rand_max = GUF_RAND_MAX >> rand_max_shift; // 2^63 - 1
const uint64_t delta = max - min;
const uint64_t delta = guf_absdiff_i64(max, min);
if (delta > rand_max) {
guf_panic(GUF_ERR_INT_OVERFLOW, GUF_ERR_MSG("in function guf_randrange_i64: interval [min, max] larger than INT64_MAX"));
return -1;

View File

@ -8,7 +8,7 @@
#define GUF_RAND32_MAX UINT32_MAX
typedef struct guf_randstate32 { // State for xoshiro256** 1.0
typedef struct guf_randstate32 { // State for xoshiro128** 1.1
uint32_t s[4];
} guf_randstate32;
@ -66,7 +66,6 @@ GUF_FN_KEYWORDS void guf_randstate32_init(guf_randstate32 *state, uint64_t seed)
if (!state->s[0] && !state->s[1] && !state->s[2] && !state->s[3]) { // State must not be only zeroes:
state->s[0] = 0x9e3779b9; // arbitrary constant != 0
seed = 0x9e3779b97f4a7c15;
split = guf_rand32_splitmix64(&seed);
state->s[0] = (uint32_t)split; // lower 32-bits
@ -174,18 +173,19 @@ GUF_FN_KEYWORDS int32_t guf_rand32range_i32(guf_randstate32 *state, int32_t min,
const unsigned rand_max_shift = 1;
const uint32_t rand_max = GUF_RAND32_MAX >> rand_max_shift; // 2^32 - 1
const uint32_t delta = max - min;
const uint32_t delta = guf_absdiff_i32(max, min);
if (delta > rand_max) {
guf_panic(GUF_ERR_INT_OVERFLOW, GUF_ERR_MSG("in function guf_randrange32_i32: interval [min, max] larger than INT32_MAX"));
return -1;
}
}
/*
cf. https://c-faq.com/lib/randrange.html (last-retrieved 2025-02-11)
https://stackoverflow.com/a/6852396 (last-retrieved 2025-02-11)
*/
const uint32_t num_rand_vals = rand_max + 1u; // 2^31
const uint32_t num_bins = (delta + 1u);
const uint32_t bin_size = num_rand_vals / num_bins; // bin_size = floor(num_rand_vals / num_bins)
const uint32_t limit = num_rand_vals - (num_rand_vals % num_bins); // limit == bin_size * num_bins
GUF_ASSERT(limit == bin_size * num_bins);