From 86705a50afd1bb317fa07181a86b18666befc219 Mon Sep 17 00:00:00 2001
From: David Abdurachmanov <david.abdurachmanov@gmail.com>
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 <david.abdurachmanov@gmail.com>
---
.../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
|
b
|
|
| 41 | 41 | #undef BOOST_NO_IO_COVER_OPERATORS |
| 42 | 42 | #undef BOOST_MINIMAL_INTEGER_COVER_OPERATORS |
| 43 | 43 | #include <boost/type_traits/is_signed.hpp> |
| | 44 | #include <boost/type_traits/make_unsigned.hpp> |
| 44 | 45 | #include <boost/cstdint.hpp> |
| 45 | 46 | #include <boost/static_assert.hpp> |
| 46 | 47 | #include <boost/spirit/home/support/detail/scoped_enum_emulation.hpp> |
| … |
… |
namespace boost { namespace spirit
|
| 70 | 71 | { |
| 71 | 72 | typedef unrolled_byte_loops<T, n_bytes - 1, sign> next; |
| 72 | 73 | |
| 73 | | static T load_big(const unsigned char* bytes) |
| | 74 | static typename boost::make_unsigned<T>::type load_big(const unsigned char* bytes) |
| 74 | 75 | { return *(bytes - 1) | (next::load_big(bytes - 1) << 8); } |
| 75 | | static T load_little(const unsigned char* bytes) |
| | 76 | static typename boost::make_unsigned<T>::type load_little(const unsigned char* bytes) |
| 76 | 77 | { return *bytes | (next::load_little(bytes + 1) << 8); } |
| 77 | 78 | |
| 78 | 79 | static void store_big(char* bytes, T value) |
| … |
… |
namespace boost { namespace spirit
|
| 104 | 105 | template <typename T> |
| 105 | 106 | struct unrolled_byte_loops<T, 1, true> |
| 106 | 107 | { |
| 107 | | static T load_big(const unsigned char* bytes) |
| 108 | | { return *reinterpret_cast<const signed char*>(bytes - 1); } |
| 109 | | static T load_little(const unsigned char* bytes) |
| 110 | | { return *reinterpret_cast<const signed char*>(bytes); } |
| | 108 | static typename boost::make_unsigned<T>::type load_big(const unsigned char* bytes) |
| | 109 | { return *(bytes - 1); } |
| | 110 | static typename boost::make_unsigned<T>::type load_little(const unsigned char* bytes) |
| | 111 | { return *bytes; } |
| 111 | 112 | static void store_big(char* bytes, T value) |
| 112 | 113 | { *(bytes - 1) = static_cast<char>(value); } |
| 113 | 114 | static void store_little(char* bytes, T value) |
| … |
… |
namespace boost { namespace spirit
|
| 118 | 119 | inline |
| 119 | 120 | T load_big_endian(const void* bytes) |
| 120 | 121 | { |
| 121 | | return unrolled_byte_loops<T, n_bytes>::load_big |
| 122 | | (static_cast<const unsigned char*>(bytes) + n_bytes); |
| | 122 | return static_cast<T>(unrolled_byte_loops<T, n_bytes>::load_big |
| | 123 | (static_cast<const unsigned char*>(bytes) + n_bytes)); |
| 123 | 124 | } |
| 124 | 125 | |
| 125 | 126 | template <> |
| … |
… |
namespace boost { namespace spirit
|
| 164 | 165 | inline |
| 165 | 166 | T load_little_endian(const void* bytes) |
| 166 | 167 | { |
| 167 | | return unrolled_byte_loops<T, n_bytes>::load_little |
| 168 | | (static_cast<const unsigned char*>(bytes)); |
| | 168 | return static_cast<T>(unrolled_byte_loops<T, n_bytes>::load_little |
| | 169 | (static_cast<const unsigned char*>(bytes))); |
| 169 | 170 | } |
| 170 | 171 | |
| 171 | 172 | template <> |