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 <> |