diff options
author | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-04-22 18:51:59 -0600 |
---|---|---|
committer | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-05-06 11:53:17 -0600 |
commit | 24e5d0ec1219e2dbb4b9510ef20833092a2b3871 (patch) | |
tree | 01bbcc34c6190fa1c35b2625e9ba1744b1447606 /libmisc/include | |
parent | f09b7435b3a5222597d27238226d23ec0cbd5bd2 (diff) |
wip: Build with -Wconversionlukeshu/safe-conversion
I think this found a real bug in the dhcp packet parser.
I don't think anything called lib9p_str{,n}() values that could be big
enough, but their bounds-checking was broken.
Diffstat (limited to 'libmisc/include')
-rw-r--r-- | libmisc/include/libmisc/macro.h | 62 | ||||
-rw-r--r-- | libmisc/include/libmisc/rand.h | 7 |
2 files changed, 61 insertions, 8 deletions
diff --git a/libmisc/include/libmisc/macro.h b/libmisc/include/libmisc/macro.h index 1712f7d..43a00f6 100644 --- a/libmisc/include/libmisc/macro.h +++ b/libmisc/include/libmisc/macro.h @@ -120,11 +120,63 @@ #define LM_BIT_XOR(a, b) ((typeof(a))(((a)^(b)) + static_assert_as_expr(__builtin_types_compatible_p(typeof(a), typeof(b))))) #define LM_BIT_FLIP(a) ((typeof(a))(~(a))) -#define LM_CEILDIV(n, d) ( ((n)+(d)-1) / (d) ) /** Return ceil(n/d) */ -#define LM_ROUND_UP(n, d) ( LM_CEILDIV(n, d) * (d) ) /** Return `n` rounded up to the nearest multiple of `d` */ -#define LM_ROUND_DOWN(n, d) ( ((n)/(d)) * (d) ) /** Return `n` rounded down to the nearest multiple of `d` */ -#define LM_NEXT_POWER_OF_2(x) ( (x) ? 1ULL<<((sizeof(unsigned long long)*8)-__builtin_clzll(x)) : 1) /** Return the lowest power of 2 that is > x */ -#define LM_FLOORLOG2(x) ((sizeof(unsigned long long)*8)-__builtin_clzll(x)-1) /** Return floor(log_2(x) */ +#define LM_CEILDIV(n, d) ( ((n)+(d)-1) / (d) ) /** Return ceil(n/d) */ +#define LM_ROUND_UP(n, d) ( LM_CEILDIV(n, d) * (d) ) /** Return `n` rounded up to the nearest multiple of `d` */ +#define LM_ROUND_DOWN(n, d) ( ((n)/(d)) * (d) ) /** Return `n` rounded down to the nearest multiple of `d` */ +#define LM_NEXT_POWER_OF_2(x) ( (x) ? 1ULL<<((sizeof(unsigned long long)*8)-(unsigned)__builtin_clzll(x)) : 1) /** Return the lowest power of 2 that is > x */ +#define LM_FLOORLOG2(x) ((sizeof(unsigned long long)*8)-(unsigned)__builtin_clzll(x)-1) /** Return floor(log_2(x) */ + +#define _LM_PROP_SIGNED(TYP) _Generic((TYP)0, \ + unsigned char : 0, \ + unsigned short : 0, \ + unsigned : 0, \ + unsigned long : 0, \ + unsigned long long : 0, \ + signed char : 1, \ + short : 1, \ + int : 1, \ + long : 1, \ + long long : 1) +#define _LM_PROP_MIN(TYP) _Generic((TYP)0, \ + unsigned char : 0, \ + unsigned short : 0, \ + unsigned : 0, \ + unsigned long : 0, \ + unsigned long long : 0, \ + signed char : SCHAR_MIN, \ + short : SHRT_MIN, \ + int : INT_MIN, \ + long : LONG_MIN, \ + long long : LLONG_MIN) +#define _LM_PROP_MAX(TYP) _Generic((TYP)0, \ + unsigned char : UCHAR_MAX, \ + unsigned short : USHRT_MAX, \ + unsigned : UINT_MAX, \ + unsigned long : ULONG_MAX, \ + unsigned long long : ULLONG_MAX, \ + signed char : SCHAR_MAX, \ + short : SHRT_MAX, \ + int : INT_MAX, \ + long : LONG_MAX, \ + long long : LLONG_MAX) + +#define LM_SAFEDOWNCAST(TYP, x) ({ \ + typeof(x) _x = (x); \ + /* Assert that it's a downcast (that this macro is being used \ + * correctly). We're a little forgiving (<= instead of <) to allow \ + * this to be used for types that are different relative sizes on \ + * different architectures. */ \ + static_assert(sizeof((TYP)0) <= sizeof(_x) || \ + _LM_PROP_SIGNED(TYP) != _LM_PROP_SIGNED(typeof(_x))); \ + /* Assert that x is within the new bounds. */ \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wtype-limits\"") \ + assert(_LM_PROP_MIN(TYP) <= _x && _x <= _LM_PROP_MAX(TYP)); \ + _Pragma("GCC diagnostic pop") \ + (TYP)_x; \ +}) + +LM_BITFLIP(TYP, x) ({ TYP _x = x; (TYP)~_x; }) /* strings */ diff --git a/libmisc/include/libmisc/rand.h b/libmisc/include/libmisc/rand.h index 784e580..b54dee0 100644 --- a/libmisc/include/libmisc/rand.h +++ b/libmisc/include/libmisc/rand.h @@ -17,13 +17,13 @@ * Return a psuedo-random number in the half-open interval [0,cnt). * `cnt` must not be greater than 1<<63. */ -static inline uint64_t rand_uint63n(uint64_t cnt) { +static inline uint64_t _rand_uint63n(uint64_t cnt) { assert(cnt != 0 && ((cnt-1) & 0x8000000000000000) == 0); if (cnt <= LM_BIT(uint64_t, 31)) { uint32_t fair_cnt = LM_ROUND_DOWN(LM_BIT(uint32_t, 31), cnt); uint32_t rnd; do { - rnd = random(); + rnd = LM_UPCAST(uint32_t, random()); } while (rnd >= fair_cnt); return rnd % cnt; } else if (cnt <= LM_BIT(uint64_t, 62)) { @@ -37,11 +37,12 @@ static inline uint64_t rand_uint63n(uint64_t cnt) { uint64_t fair_cnt = LM_ROUND_DOWN(LM_BIT(uint64_t, 63), cnt); uint64_t rnd; do { - rnd = (LM_UPCAST(uint64_t, random()) << 62) | (LM_UPCAST(uint64_t, random()) << 31) | LM_UPCAST(random(); + rnd = (LM_UPCAST(uint64_t, random()) << 62) | (LM_UPCAST(uint64_t, random()) << 31) | LM_UPCAST(uint64_t, random()); } while (rnd >= fair_cnt); return rnd % cnt; } assert_notreached("cnt is out of bounds"); } +#define rand_uint63n(cnt) ((typeof(cnt))_rand_uint63n(cnt)) #endif /* _LIBMISC_RAND_H_ */ |