lib: endianness: don't break strict-aliasing

Strict aliasing prohibits writing to union members of one type, then
reading another type.  The read is undefined.  Use memcpy instead (which
compilers will hopefully optimize away...)
This commit is contained in:
David Lamparter 2016-06-22 14:22:11 +02:00
parent 0abd16d62c
commit 1afce9573a

View file

@ -13,6 +13,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <string.h>
#if defined(unix) && !defined(__APPLE__) #if defined(unix) && !defined(__APPLE__)
#include <endian.h> #include <endian.h>
#endif #endif
@ -316,10 +317,12 @@ CAPN_INLINE uint16_t capn_flip16(uint16_t v) {
defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 8 defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 8
return __builtin_bswap16(v); return __builtin_bswap16(v);
#else #else
union { uint16_t u; uint8_t v[2]; } s; uint8_t sv[2];
s.v[0] = (uint8_t)v; uint16_t ret;
s.v[1] = (uint8_t)(v>>8); sv[0] = (uint8_t)v;
return s.u; sv[1] = (uint8_t)(v>>8);
memcpy(&ret, sv, sizeof(ret));
return ret;
#endif #endif
} }
CAPN_INLINE uint32_t capn_flip32(uint32_t v) { CAPN_INLINE uint32_t capn_flip32(uint32_t v) {
@ -329,12 +332,14 @@ CAPN_INLINE uint32_t capn_flip32(uint32_t v) {
defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 8 defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 8
return __builtin_bswap32(v); return __builtin_bswap32(v);
#else #else
union { uint32_t u; uint8_t v[4]; } s; uint8_t sv[4];
s.v[0] = (uint8_t)v; uint32_t ret;
s.v[1] = (uint8_t)(v>>8); sv[0] = (uint8_t)v;
s.v[2] = (uint8_t)(v>>16); sv[1] = (uint8_t)(v>>8);
s.v[3] = (uint8_t)(v>>24); sv[2] = (uint8_t)(v>>16);
return s.u; sv[3] = (uint8_t)(v>>24);
memcpy(&ret, sv, sizeof(ret));
return ret;
#endif #endif
} }
CAPN_INLINE uint64_t capn_flip64(uint64_t v) { CAPN_INLINE uint64_t capn_flip64(uint64_t v) {
@ -344,16 +349,18 @@ CAPN_INLINE uint64_t capn_flip64(uint64_t v) {
defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 8 defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 8
return __builtin_bswap64(v); return __builtin_bswap64(v);
#else #else
union { uint64_t u; uint8_t v[8]; } s; uint8_t sv[8];
s.v[0] = (uint8_t)v; uint64_t ret;
s.v[1] = (uint8_t)(v>>8); sv[0] = (uint8_t)v;
s.v[2] = (uint8_t)(v>>16); sv[1] = (uint8_t)(v>>8);
s.v[3] = (uint8_t)(v>>24); sv[2] = (uint8_t)(v>>16);
s.v[4] = (uint8_t)(v>>32); sv[3] = (uint8_t)(v>>24);
s.v[5] = (uint8_t)(v>>40); sv[4] = (uint8_t)(v>>32);
s.v[6] = (uint8_t)(v>>48); sv[5] = (uint8_t)(v>>40);
s.v[7] = (uint8_t)(v>>56); sv[6] = (uint8_t)(v>>48);
return s.u; sv[7] = (uint8_t)(v>>56);
memcpy(&ret, sv, sizeof(ret));
return ret;
#endif #endif
} }