From 86705a50afd1bb317fa07181a86b18666befc219 Mon Sep 17 00:00:00 2001 From: David Abdurachmanov Date: Mon, 19 Oct 2015 07:46:57 +0000 Subject: [PATCH] Fix undefined behavior in ../support/detail/endian/endian.hpp (#11726) Undefined behavior sanitizer (UBSan) with GCC 5.1.1 complains about left shifting of negative value at run-time. This happens once boost::spirit::detail::load_little_endian is used with a singed type. The patch resolves the issue by using unsigned type for making left shifts, then load_little_endian casts it to specific type T. Tested with Clang and GCC locally (test case in #11726) and all worked fine. Tested by running all Boost test cases before and after, no regressions. Signed-off-by: David Abdurachmanov --- .../spirit/home/support/detail/endian/endian.hpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/include/boost/spirit/home/support/detail/endian/endian.hpp b/include/boost/spirit/home/support/detail/endian/endian.hpp index c806b58..ac1c13f 100644 --- a/include/boost/spirit/home/support/detail/endian/endian.hpp +++ b/include/boost/spirit/home/support/detail/endian/endian.hpp @@ -41,6 +41,7 @@ #undef BOOST_NO_IO_COVER_OPERATORS #undef BOOST_MINIMAL_INTEGER_COVER_OPERATORS #include +#include #include #include #include @@ -70,9 +71,9 @@ namespace boost { namespace spirit { typedef unrolled_byte_loops next; - static T load_big(const unsigned char* bytes) + static typename boost::make_unsigned::type load_big(const unsigned char* bytes) { return *(bytes - 1) | (next::load_big(bytes - 1) << 8); } - static T load_little(const unsigned char* bytes) + static typename boost::make_unsigned::type load_little(const unsigned char* bytes) { return *bytes | (next::load_little(bytes + 1) << 8); } static void store_big(char* bytes, T value) @@ -104,10 +105,10 @@ namespace boost { namespace spirit template struct unrolled_byte_loops { - static T load_big(const unsigned char* bytes) - { return *reinterpret_cast(bytes - 1); } - static T load_little(const unsigned char* bytes) - { return *reinterpret_cast(bytes); } + static typename boost::make_unsigned::type load_big(const unsigned char* bytes) + { return *(bytes - 1); } + static typename boost::make_unsigned::type load_little(const unsigned char* bytes) + { return *bytes; } static void store_big(char* bytes, T value) { *(bytes - 1) = static_cast(value); } static void store_little(char* bytes, T value) @@ -118,8 +119,8 @@ namespace boost { namespace spirit inline T load_big_endian(const void* bytes) { - return unrolled_byte_loops::load_big - (static_cast(bytes) + n_bytes); + return static_cast(unrolled_byte_loops::load_big + (static_cast(bytes) + n_bytes)); } template <> @@ -164,8 +165,8 @@ namespace boost { namespace spirit inline T load_little_endian(const void* bytes) { - return unrolled_byte_loops::load_little - (static_cast(bytes)); + return static_cast(unrolled_byte_loops::load_little + (static_cast(bytes))); } template <> -- 2.4.3