From 8db0450dcc32575be6153e12761888a6089c27fe Mon Sep 17 00:00:00 2001 From: David Chisnall Date: Fri, 25 Jan 2019 16:36:28 +0000 Subject: [PATCH] Fix bug in ivar align computation. __builtin_clz takes an unsigned int, it isn't overloaded for different types. This meant that we were computing log2 by counting the leading bits in a 32-bit value and using that result as if it were the number of bits in a 64-bit value. This meant that our alignment values were 2^32 times as big as they should be. This mostly didn't matter, because we then truncated the result to 32 bits and the wrapping gave the correct answer. Unfortunately, this was undefined behaviour and, at sufficiently high optimisation levels, this resulted in the value being optimised away, leading to odd results. --- ivar.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ivar.h b/ivar.h index 9f41af3..367e57b 100644 --- a/ivar.h +++ b/ivar.h @@ -94,7 +94,15 @@ static inline void ivarSetAlign(Ivar ivar, size_t align) { if (align != 0) { - align = sizeof(size_t) * 8 - __builtin_clz(align) - 1; + if (sizeof(size_t) == 4) + { + align = 4 * 8 - __builtin_clz(align) - 1; + } + else if (sizeof(size_t) == 8) + { + align = 8 * 8 - __builtin_clzll(align) - 1; + } + _Static_assert((sizeof(size_t) == 4) || (sizeof(size_t) == 8), "Unexpected type for size_t"); } align <<= ivar_align_shift; ivar->flags = (ivar->flags & ~ivar_align_mask) | align;