From f4eab220704de61fb51424eea225317c91ce5d2f Mon Sep 17 00:00:00 2001 From: Hugo Hurskainen Date: Sun, 14 Jun 2026 23:36:50 +0300 Subject: [PATCH] refactor: replace byte-swap macros with static inline functions The ltfs_betou*/ltfs_u*tobe macros cast byte buffers to uint16_t/uint32_t and dereferenced them, e.g. *(uint32_t *)(buf). Callers pass buffers at arbitrary offsets (cdb + 3, coh_data + 6), so these were unaligned accesses -- undefined behaviour that happens to work on x86 but faults (SIGBUS) or returns rotated/garbage data on alignment-strict CPUs, and trips UBSan. Convert each to a static inline function that moves bytes through memcpy, which is well defined for any alignment and lowers to a single load/store plus byte swap, so there is no runtime cost. Using functions instead of macros also: - Adds real type checking: parameters and return values have concrete types (void */const void * buffers, fixed-width integers) instead of textual substitution, so passing the wrong type is caught at compile time rather than silently reinterpreted. - Produces clearer compiler errors: diagnostics point at the call site and the function signature instead of deep inside a macro expansion. - Evaluates each argument exactly once and needs no defensive parentheses, removing the double-evaluation and operator-precedence hazards that the old ltfs_betou64 macro had. The signatures are unchanged, so all call sites are untouched. Add and so the header is self-contained. --- src/libltfs/ltfs_endian.h | 66 ++++++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 19 deletions(-) diff --git a/src/libltfs/ltfs_endian.h b/src/libltfs/ltfs_endian.h index 9296c10c..fa3c619a 100644 --- a/src/libltfs/ltfs_endian.h +++ b/src/libltfs/ltfs_endian.h @@ -48,6 +48,9 @@ #ifndef __LTFS_ENDIAN_H__ #define __LTFS_ENDIAN_H__ +#include +#include + /* TODO: verify that this is correct for mingw */ #ifdef mingw_PLATFORM #include @@ -55,54 +58,79 @@ #include #endif /* mingw_PLATFORM */ +/* + * These were function-like macros that cast the buffer to uint16_t/uint32_t and + * dereferenced it directly. Buffers are byte arrays accessed at arbitrary offsets + * (e.g. cdb + 3), so those casts performed unaligned accesses, which are undefined + * behaviour and fault on architectures that require natural alignment. They are now + * static inline functions that copy through memcpy; the compiler lowers each fixed + * size memcpy to a single load/store (plus a byte swap), so there is no overhead. + */ + /** * Convert a uint64_t value (src) to big endian and store it in the 8-byte buffer * pointed to by dest. */ -#define ltfs_u64tobe(dest, src) \ - do { \ - uint32_t *tmp = (uint32_t *)(dest); \ - uint64_t stmp = (src); \ - tmp[0] = htonl((stmp >> 32) & 0xffffffff); \ - tmp[1] = htonl(stmp & 0xffffffff); \ - } while (0) +static inline void ltfs_u64tobe(void *dest, uint64_t src) +{ + uint32_t tmp[2]; + tmp[0] = htonl((uint32_t)((src >> 32) & 0xffffffff)); + tmp[1] = htonl((uint32_t)(src & 0xffffffff)); + memcpy(dest, tmp, sizeof(tmp)); +} /** * Convert a uint32_t value (src) to big endian and store it in the 4-byte buffer * pointed to by dest. */ -#define ltfs_u32tobe(dest, src) \ - do { \ - *((uint32_t *)(dest)) = htonl((src)); \ - } while (0) +static inline void ltfs_u32tobe(void *dest, uint32_t src) +{ + uint32_t tmp = htonl(src); + memcpy(dest, &tmp, sizeof(tmp)); +} /** * Convert a uint16_t value (src) to big endian and store it in the 2-byte buffer * pointed to by dest. */ -#define ltfs_u16tobe(dest, src) \ - do { \ - *((uint16_t *)(dest)) = htons((src)); \ - } while (0) +static inline void ltfs_u16tobe(void *dest, uint16_t src) +{ + uint16_t tmp = htons(src); + memcpy(dest, &tmp, sizeof(tmp)); +} /** * Convert a big endian 64-bit unsigned integer (pointed to by buf) * to a uint64_t in local byte order. */ -#define ltfs_betou64(buf) \ - (((uint64_t)ntohl(*((uint32_t *)(buf)))) << 32) + (uint64_t)ntohl(*(((uint32_t *)(buf))+1)) +static inline uint64_t ltfs_betou64(const void *buf) +{ + uint32_t tmp[2]; + memcpy(tmp, buf, sizeof(tmp)); + return ((uint64_t)ntohl(tmp[0]) << 32) | (uint64_t)ntohl(tmp[1]); +} /** * Convert a big endian 32-bit unsigned integer (pointed to by buf) * to a uint32_t in local byte order. */ -#define ltfs_betou32(buf) ntohl(*((uint32_t *)(buf))) +static inline uint32_t ltfs_betou32(const void *buf) +{ + uint32_t tmp; + memcpy(&tmp, buf, sizeof(tmp)); + return ntohl(tmp); +} /** * Convert a big endian 16-bit unsigned integer (pointed to by buf) * to a uint16_t in local byte order. */ -#define ltfs_betou16(buf) ntohs(*((uint16_t *)(buf))) +static inline uint16_t ltfs_betou16(const void *buf) +{ + uint16_t tmp; + memcpy(&tmp, buf, sizeof(tmp)); + return ntohs(tmp); +} #endif /* __LTFS_ENDIAN_H__ */