From 6adaf5ca27534d5736be384e51750f0df4c6249a Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Wed, 8 Jun 2022 16:29:44 +0100 Subject: [PATCH] Fix aliasing violations in ip6_and Accessing uint8_t[16] through a different type is an aliasing violation, i.e. undefined behaviour. Use memcpy to copy the bytes out, then AND them, then memcpy back in. The actual memcpy calls will be optimized away, but doing it this way avoids undefined behaviour. --- ip2net/ip2net.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/ip2net/ip2net.c b/ip2net/ip2net.c index ee57fd7..dede7e7 100644 --- a/ip2net/ip2net.c +++ b/ip2net/ip2net.c @@ -105,16 +105,12 @@ static inline const struct in6_addr *mask_from_bitcount6(uint32_t zct) // result = a & b static void ip6_and(const struct in6_addr *a, const struct in6_addr *b, struct in6_addr *result) { - // POSSIBLE GCC COMPILER BUG . when using uint64_t and -O2/-O3 optimizations this function gets inlined with the wrong code and produces wrong results -#if defined(__GNUC__) && !defined(__llvm__) && !defined(__NO_INLINE__) - ((uint32_t*)result->s6_addr)[0] = ((uint32_t*)a->s6_addr)[0] & ((uint32_t*)b->s6_addr)[0]; - ((uint32_t*)result->s6_addr)[1] = ((uint32_t*)a->s6_addr)[1] & ((uint32_t*)b->s6_addr)[1]; - ((uint32_t*)result->s6_addr)[2] = ((uint32_t*)a->s6_addr)[2] & ((uint32_t*)b->s6_addr)[2]; - ((uint32_t*)result->s6_addr)[3] = ((uint32_t*)a->s6_addr)[3] & ((uint32_t*)b->s6_addr)[3]; -#else - ((uint64_t*)result->s6_addr)[0] = ((uint64_t*)a->s6_addr)[0] & ((uint64_t*)b->s6_addr)[0]; - ((uint64_t*)result->s6_addr)[1] = ((uint64_t*)a->s6_addr)[1] & ((uint64_t*)b->s6_addr)[1]; -#endif + uint64_t a_addr[2], b_addr[2]; + memcpy(a_addr, a->s6_addr, 16); + memcpy(b_addr, b->s6_addr, 16); + a_addr[0] &= b_addr[0]; + a_addr[1] &= b_addr[1]; + memcpy(result->s6_addr, a_addr, 16); } static void rtrim(char *s)