Skip to content

Commit 0e2208d

Browse files
committed
Harden byte order detection
Use __BYTE_ORDER__ for GCC/Clang, and include Linux/BSD-specific headers for endian detection, and a constexpr static_assert instead of silently defaulting to little-endian. Fixes #135.
1 parent af2f6e2 commit 0e2208d

1 file changed

Lines changed: 54 additions & 7 deletions

File tree

include/protozero/config.hpp

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,66 @@ documentation.
2222
#define PROTOZERO_BIG_ENDIAN 4321
2323

2424
// Find out which byte order the machine has.
25-
#if defined(__BYTE_ORDER)
26-
# if (__BYTE_ORDER == __LITTLE_ENDIAN)
25+
26+
// __BYTE_ORDER__ is set by GCC and Clang.
27+
#if !defined(PROTOZERO_BYTE_ORDER) && defined(__BYTE_ORDER__)
28+
# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
2729
# define PROTOZERO_BYTE_ORDER PROTOZERO_LITTLE_ENDIAN
28-
# endif
29-
# if (__BYTE_ORDER == __BIG_ENDIAN)
30+
# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
3031
# define PROTOZERO_BYTE_ORDER PROTOZERO_BIG_ENDIAN
3132
# endif
32-
#else
33-
// This probably isn't a very good default, but might do until we figure
34-
// out something better.
33+
#endif // defined(__BYTE_ORDER__)
34+
35+
// On Linux, we can use endian.h.
36+
#if !defined(PROTOZERO_BYTE_ORDER) && defined(__linux__)
37+
# include <endian.h>
38+
# if defined(__BYTE_ORDER)
39+
# if (__BYTE_ORDER == __LITTLE_ENDIAN)
40+
# define PROTOZERO_BYTE_ORDER PROTOZERO_LITTLE_ENDIAN
41+
# elif (__BYTE_ORDER == __BIG_ENDIAN)
42+
# define PROTOZERO_BYTE_ORDER PROTOZERO_BIG_ENDIAN
43+
# endif
44+
# endif
45+
#endif // !defined(PROTOZERO_BYTE_ORDER) && defined(__linux__)
46+
47+
// On BSD, we can use <sys/endian.h>
48+
#if !defined(PROTOZERO_BYTE_ORDER) && \
49+
(defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__))
50+
# include <sys/endian.h>
51+
# if defined(BYTE_ORDER)
52+
# if (BYTE_ORDER == LITTLE_ENDIAN)
53+
# define PROTOZERO_BYTE_ORDER PROTOZERO_LITTLE_ENDIAN
54+
# elif (BYTE_ORDER == BIG_ENDIAN)
55+
# define PROTOZERO_BYTE_ORDER PROTOZERO_BIG_ENDIAN
56+
# endif
57+
# endif
58+
#endif
59+
60+
// On Windows, we assume little endian.
61+
#if !defined(PROTOZERO_BYTE_ORDER) && defined(_MSC_VER)
3562
# define PROTOZERO_BYTE_ORDER PROTOZERO_LITTLE_ENDIAN
63+
#endif // !defined(PROTOZERO_BYTE_ORDER) && defined(_MSC_VER)
64+
65+
#if !defined(PROTOZERO_BYTE_ORDER)
66+
# error "Could not determine byte order; define PROTOZERO_BYTE_ORDER"
3667
#endif
3768

69+
namespace protozero {
70+
namespace detail {
71+
72+
constexpr bool is_little_endian() noexcept {
73+
return static_cast<unsigned char const&>(
74+
static_cast<unsigned int const&>(1u)) == 1u;
75+
}
76+
77+
} // namespace detail
78+
} // namespace protozero
79+
80+
static_assert(
81+
protozero::detail::is_little_endian() ==
82+
(PROTOZERO_BYTE_ORDER == PROTOZERO_LITTLE_ENDIAN),
83+
"Could not determine byte order correctly; define PROTOZERO_BYTE_ORDER");
84+
3885
// Check whether __builtin_bswap is available
3986
#if defined(__GNUC__) || defined(__clang__)
4087
# define PROTOZERO_USE_BUILTIN_BSWAP

0 commit comments

Comments
 (0)