summaryrefslogtreecommitdiff
path: root/libmisc/include
diff options
context:
space:
mode:
authorLuke T. Shumaker <lukeshu@lukeshu.com>2025-04-22 18:51:59 -0600
committerLuke T. Shumaker <lukeshu@lukeshu.com>2025-05-06 11:53:17 -0600
commit24e5d0ec1219e2dbb4b9510ef20833092a2b3871 (patch)
tree01bbcc34c6190fa1c35b2625e9ba1744b1447606 /libmisc/include
parentf09b7435b3a5222597d27238226d23ec0cbd5bd2 (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.h62
-rw-r--r--libmisc/include/libmisc/rand.h7
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_ */