Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(265)

Side by Side Diff: webrtc/modules/rtp_rtcp/source/byte_io.h

Issue 1226993003: Refactor byte_io to avoid potentially undefined behavior (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Use numeric limits to get signed min-val Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source 5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 10
(...skipping 24 matching lines...) Expand all
35 // These classes are implemented as recursive templetizations, inteded to make 35 // These classes are implemented as recursive templetizations, inteded to make
36 // it easy for the compiler to completely inline the reading/writing. 36 // it easy for the compiler to completely inline the reading/writing.
37 37
38 38
39 #include <limits> 39 #include <limits>
40 40
41 #include "webrtc/typedefs.h" 41 #include "webrtc/typedefs.h"
42 42
43 namespace webrtc { 43 namespace webrtc {
44 44
45 // According to ISO C standard ISO/IEC 9899, section 6.2.6.2 (2), the three
46 // representations of signed integers allowed are two's complement, one's
47 // complement and sign/magnitude. We can detect which is used by looking at
48 // the two last bits of -1, which will be 11 in two's complement, 10 in one's
49 // complement and 01 in sign/magnitude.
50 // TODO(sprang): In the unlikely event that we actually need to support a
51 // platform that doesn't use two's complement, implement conversion to/from
52 // wire format.
53
54 namespace {
55 inline void AssertTwosComplement() {
56 // Assume the if any one signed integer type is two's complement, then all
57 // other will be too.
58 static_assert(
59 (-1 & 0x03) == 0x03,
60 "Only two's complement representation of signed integers supported.");
61 }
62 // Plain const char* won't work for static_assert, use #define instead.
63 #define kSizeErrorMsg "Byte size must be less than or equal to data type size."
64 }
65
66 // Utility class for getting the unsigned equivalent of a signed type.
67 template <typename T>
68 struct UnsignedOf;
69
45 // Class for reading integers from a sequence of bytes. 70 // Class for reading integers from a sequence of bytes.
46 // T = type of integer, B = bytes to read, is_signed = true if signed integer 71 // T = type of integer, B = bytes to read, is_signed = true if signed integer.
47 // If is_signed is true and B < sizeof(T), sign extension might be needed 72 // If is_signed is true and B < sizeof(T), sign extension might be needed.
48 template<typename T, unsigned int B = sizeof(T), 73 template <typename T,
49 bool is_signed = std::numeric_limits<T>::is_signed> 74 unsigned int B = sizeof(T),
50 class ByteReader { 75 bool is_signed = std::numeric_limits<T>::is_signed>
76 class ByteReader;
77
78 // Specialization of ByteReader for unsigned types.
79 template <typename T, unsigned int B>
80 class ByteReader<T, B, false> {
51 public: 81 public:
52 static T ReadBigEndian(const uint8_t* data) { 82 static T ReadBigEndian(const uint8_t* data) {
53 if (is_signed && B < sizeof(T)) { 83 static_assert(B <= sizeof(T), kSizeErrorMsg);
54 return SignExtend(InternalReadBigEndian(data));
55 }
56 return InternalReadBigEndian(data); 84 return InternalReadBigEndian(data);
57 } 85 }
58 86
59 static T ReadLittleEndian(const uint8_t* data) { 87 static T ReadLittleEndian(const uint8_t* data) {
60 if (is_signed && B < sizeof(T)) { 88 static_assert(B <= sizeof(T), kSizeErrorMsg);
61 return SignExtend(InternalReadLittleEndian(data));
62 }
63 return InternalReadLittleEndian(data); 89 return InternalReadLittleEndian(data);
64 } 90 }
65 91
66 private: 92 private:
67 static T InternalReadBigEndian(const uint8_t* data) { 93 static T InternalReadBigEndian(const uint8_t* data) {
68 T val(0); 94 T val(0);
69 for (unsigned int i = 0; i < B; ++i) { 95 for (unsigned int i = 0; i < B; ++i)
70 val |= static_cast<T>(data[i]) << ((B - 1 - i) * 8); 96 val |= static_cast<T>(data[i]) << ((B - 1 - i) * 8);
71 }
72 return val; 97 return val;
73 } 98 }
74 99
75 static T InternalReadLittleEndian(const uint8_t* data) { 100 static T InternalReadLittleEndian(const uint8_t* data) {
76 T val(0); 101 T val(0);
77 for (unsigned int i = 0; i < B; ++i) { 102 for (unsigned int i = 0; i < B; ++i)
78 val |= static_cast<T>(data[i]) << (i * 8); 103 val |= static_cast<T>(data[i]) << (i * 8);
104 return val;
105 }
106 };
107
108 // Specialization of ByteReader for signed types.
109 template <typename T, unsigned int B>
110 class ByteReader<T, B, true> {
111 public:
112 typedef typename UnsignedOf<T>::Type U;
113
114 static T ReadBigEndian(const uint8_t* data) {
115 U unsigned_val = ByteReader<T, B, false>::ReadBigEndian(data);
116 if (B < sizeof(T))
117 unsigned_val = SignExtend(unsigned_val);
118 return ReinterpretAsSigned(unsigned_val);
119 }
120
121 static T ReadLittleEndian(const uint8_t* data) {
122 U unsigned_val = ByteReader<T, B, false>::ReadLittleEndian(data);
123 if (B < sizeof(T))
124 unsigned_val = SignExtend(unsigned_val);
125 return ReinterpretAsSigned(unsigned_val);
126 }
127
128 private:
129 // As a hack to avoid implementation-specific or undefined behavior when
130 // bit-shifting or casting signed integers, read as a signed equivalent
131 // instead and convert to signed. This is safe since we have asserted that
132 // two's complement for is used.
133 static T ReinterpretAsSigned(U unsigned_val) {
134 // An unsigned value with only the highest order bit set (ex 0x80).
135 const U kUnsignedHighestBitMask =
136 static_cast<U>(1) << ((sizeof(U) * 8) - 1);
137 // A signed value with only the highest bit set. Since this is two's
138 // complement form, we can use the min value from std::numeric_limits.
139 const T kSignedHighestBitMask = std::numeric_limits<T>::min();
140
141 T val;
142 if ((unsigned_val & kUnsignedHighestBitMask) != 0) {
143 // Casting is only safe when unsigned value can be represented in the
144 // signed target type, so mask out highest bit and mask it back manually.
145 val = static_cast<T>(unsigned_val & ~kUnsignedHighestBitMask);
146 val |= kSignedHighestBitMask;
147 } else {
148 val = static_cast<T>(unsigned_val);
79 } 149 }
80 return val; 150 return val;
81 } 151 }
82 152
83 // If number of bytes is less than native data type (eg 24 bit, in int32_t), 153 // If number of bytes is less than native data type (eg 24 bit, in int32_t),
84 // and the most significant bit of the actual data is set, we must sign 154 // and the most significant bit of the actual data is set, we must sign
85 // extend the remaining byte(s) with ones so that the correct negative 155 // extend the remaining byte(s) with ones so that the correct negative
86 // number is retained. 156 // number is retained.
87 // Ex: 0x810A0B -> 0xFF810A0B, but 0x710A0B -> 0x00710A0B 157 // Ex: 0x810A0B -> 0xFF810A0B, but 0x710A0B -> 0x00710A0B
88 static T SignExtend(const T val) { 158 static U SignExtend(const U val) {
89 uint8_t msb = static_cast<uint8_t>(val >> ((B - 1) * 8)); 159 const uint8_t kMsb = static_cast<uint8_t>(val >> ((B - 1) * 8));
90 if (msb & 0x80) { 160 if ((kMsb & 0x80) != 0) {
91 // Sign extension is -1 (all ones) shifted left B bytes. 161 // Create a mask where all bits used by the B bytes are set to one,
92 // The "B % sizeof(T)"-part is there to avoid compiler warning for 162 // for instance 0x00FFFFFF for B = 3. Bit-wise invert that mask (to
93 // shifting the whole size of the data type. 163 // (0xFF000000 in the example above) and add it to the input value.
94 T sign_extend = (sizeof(T) == B ? 0 : 164 // The "B % sizeof(T)" is a workaround to undefined values warnings for
95 (static_cast<T>(-1L) << ((B % sizeof(T)) * 8))); 165 // B == sizeof(T), in which case this code won't be called anyway.
96 166 const U kUsedBitsMask = (1 << ((B % sizeof(T)) * 8)) - 1;
97 return val | sign_extend; 167 return ~kUsedBitsMask | val;
98 } 168 }
99 return val; 169 return val;
100 } 170 }
101 }; 171 };
102 172
103 // Class for writing integers to a sequence of bytes 173 // Class for writing integers to a sequence of bytes
104 // T = type of integer, B = bytes to write 174 // T = type of integer, B = bytes to write
105 template<typename T, unsigned int B = sizeof(T)> 175 template <typename T,
106 class ByteWriter { 176 unsigned int B = sizeof(T),
177 bool is_signed = std::numeric_limits<T>::is_signed>
178 class ByteWriter;
179
180 // Specialization of ByteWriter for unsigned types.
181 template <typename T, unsigned int B>
182 class ByteWriter<T, B, false> {
107 public: 183 public:
108 static void WriteBigEndian(uint8_t* data, T val) { 184 static void WriteBigEndian(uint8_t* data, T val) {
185 static_assert(B <= sizeof(T), kSizeErrorMsg);
109 for (unsigned int i = 0; i < B; ++i) { 186 for (unsigned int i = 0; i < B; ++i) {
110 data[i] = val >> ((B - 1 - i) * 8); 187 data[i] = val >> ((B - 1 - i) * 8);
111 } 188 }
112 } 189 }
113 190
114 static void WriteLittleEndian(uint8_t* data, T val) { 191 static void WriteLittleEndian(uint8_t* data, T val) {
192 static_assert(B <= sizeof(T), kSizeErrorMsg);
115 for (unsigned int i = 0; i < B; ++i) { 193 for (unsigned int i = 0; i < B; ++i) {
116 data[i] = val >> (i * 8); 194 data[i] = val >> (i * 8);
117 } 195 }
118 } 196 }
119 }; 197 };
120 198
199 // Specialization of ByteWriter for signed types.
200 template <typename T, unsigned int B>
201 class ByteWriter<T, B, true> {
202 public:
203 typedef typename UnsignedOf<T>::Type U;
121 204
122 // -------- Below follows specializations for B in { 2, 4, 8 } -------- 205 static void WriteBigEndian(uint8_t* data, T val) {
206 ByteWriter<U, B, false>::WriteBigEndian(data, ReinterpretAsUnsigned(val));
207 }
123 208
209 static void WriteLittleEndian(uint8_t* data, T val) {
210 ByteWriter<U, B, false>::WriteLittleEndian(data,
211 ReinterpretAsUnsigned(val));
212 }
213
214 private:
215 static U ReinterpretAsUnsigned(T val) {
216 // According to ISO C standard ISO/IEC 9899, section 6.3.1.3 (1, 2) a
217 // conversion from signed to unsigned keeps the value if the new type can
218 // represent it, and otherwise adds one more than the max value of T until
219 // the value is in range. For two's complement, this fortunately means
220 // that the bit-wise value will be intact. Thus, since we have asserted that
221 // two's complement form is actually used, a simple cast is sufficient.
222 return static_cast<U>(val);
223 }
224 };
225
226 // ----- Below follows specializations of UnsignedOf utility class -----
227
228 template <>
229 struct UnsignedOf<int8_t> {
230 typedef uint8_t Type;
231 };
232 template <>
233 struct UnsignedOf<int16_t> {
234 typedef uint16_t Type;
235 };
236 template <>
237 struct UnsignedOf<int32_t> {
238 typedef uint32_t Type;
239 };
240 template <>
241 struct UnsignedOf<int64_t> {
242 typedef uint64_t Type;
243 };
244
245 // ----- Below follows specializations for unsigned, B in { 1, 2, 4, 8 } -----
246
247 // TODO(sprang): Check if these actually help or if generic cases will be
pbos-webrtc 2015/09/03 15:18:08 Do you want to add these before you know that it's
sprang_webrtc 2015/09/04 07:24:06 With this comment I meant all the specializations
248 // unrolled to and optimized to similar performance.
249
250 // Specializations for single bytes
251 template <typename T>
252 class ByteReader<T, 1, false> {
253 public:
254 static T ReadBigEndian(const uint8_t* data) {
255 static_assert(sizeof(T) == 1, kSizeErrorMsg);
256 return data[0];
257 }
258
259 static T ReadLittleEndian(const uint8_t* data) {
260 static_assert(sizeof(T) == 1, kSizeErrorMsg);
261 return data[0];
262 }
263 };
264
265 template <typename T>
266 class ByteWriter<T, 1, false> {
267 public:
268 static void WriteBigEndian(uint8_t* data, T val) {
269 static_assert(sizeof(T) == 1, kSizeErrorMsg);
270 data[0] = val;
271 }
272
273 static void WriteLittleEndian(uint8_t* data, T val) {
274 static_assert(sizeof(T) == 1, kSizeErrorMsg);
275 data[0] = val;
276 }
277 };
124 278
125 // Specializations for two byte words 279 // Specializations for two byte words
126 template<typename T, bool is_signed> 280 template <typename T>
127 class ByteReader<T, 2, is_signed> { 281 class ByteReader<T, 2, false> {
128 public: 282 public:
129 static T ReadBigEndian(const uint8_t* data) { 283 static T ReadBigEndian(const uint8_t* data) {
284 static_assert(sizeof(T) >= 2, kSizeErrorMsg);
130 return (data[0] << 8) | data[1]; 285 return (data[0] << 8) | data[1];
131 } 286 }
132 287
133 static T ReadLittleEndian(const uint8_t* data) { 288 static T ReadLittleEndian(const uint8_t* data) {
289 static_assert(sizeof(T) >= 2, kSizeErrorMsg);
134 return data[0] | (data[1] << 8); 290 return data[0] | (data[1] << 8);
135 } 291 }
136 }; 292 };
137 293
138 template<typename T> 294 template <typename T>
139 class ByteWriter<T, 2> { 295 class ByteWriter<T, 2, false> {
140 public: 296 public:
141 static void WriteBigEndian(uint8_t* data, T val) { 297 static void WriteBigEndian(uint8_t* data, T val) {
298 static_assert(sizeof(T) >= 2, kSizeErrorMsg);
142 data[0] = val >> 8; 299 data[0] = val >> 8;
143 data[1] = val; 300 data[1] = val;
144 } 301 }
145 302
146 static void WriteLittleEndian(uint8_t* data, T val) { 303 static void WriteLittleEndian(uint8_t* data, T val) {
304 static_assert(sizeof(T) >= 2, kSizeErrorMsg);
147 data[0] = val; 305 data[0] = val;
148 data[1] = val >> 8; 306 data[1] = val >> 8;
149 } 307 }
150 }; 308 };
151 309
152 // Specializations for four byte words. 310 // Specializations for four byte words.
153 template<typename T, bool is_signed> 311 template <typename T>
154 class ByteReader<T, 4, is_signed> { 312 class ByteReader<T, 4, false> {
155 public: 313 public:
156 static T ReadBigEndian(const uint8_t* data) { 314 static T ReadBigEndian(const uint8_t* data) {
315 static_assert(sizeof(T) >= 4, kSizeErrorMsg);
157 return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; 316 return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
158 } 317 }
159 318
160 static T ReadLittleEndian(const uint8_t* data) { 319 static T ReadLittleEndian(const uint8_t* data) {
320 static_assert(sizeof(T) >= 4, kSizeErrorMsg);
161 return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); 321 return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
162 } 322 }
163 }; 323 };
164 324
165 // Specializations for four byte words. 325 // Specializations for four byte words.
166 template<typename T> 326 template <typename T>
167 class ByteWriter<T, 4> { 327 class ByteWriter<T, 4, false> {
168 public: 328 public:
169 static void WriteBigEndian(uint8_t* data, T val) { 329 static void WriteBigEndian(uint8_t* data, T val) {
330 static_assert(sizeof(T) >= 4, kSizeErrorMsg);
170 data[0] = val >> 24; 331 data[0] = val >> 24;
171 data[1] = val >> 16; 332 data[1] = val >> 16;
172 data[2] = val >> 8; 333 data[2] = val >> 8;
173 data[3] = val; 334 data[3] = val;
174 } 335 }
175 336
176 static void WriteLittleEndian(uint8_t* data, T val) { 337 static void WriteLittleEndian(uint8_t* data, T val) {
338 static_assert(sizeof(T) >= 4, kSizeErrorMsg);
177 data[0] = val; 339 data[0] = val;
178 data[1] = val >> 8; 340 data[1] = val >> 8;
179 data[2] = val >> 16; 341 data[2] = val >> 16;
180 data[3] = val >> 24; 342 data[3] = val >> 24;
181 } 343 }
182 }; 344 };
183 345
184 // Specializations for eight byte words. 346 // Specializations for eight byte words.
185 template<typename T, bool is_signed> 347 template <typename T>
186 class ByteReader<T, 8, is_signed> { 348 class ByteReader<T, 8, false> {
187 public: 349 public:
188 static T ReadBigEndian(const uint8_t* data) { 350 static T ReadBigEndian(const uint8_t* data) {
351 static_assert(sizeof(T) >= 8, kSizeErrorMsg);
189 return 352 return
190 (Get(data, 0) << 56) | (Get(data, 1) << 48) | 353 (Get(data, 0) << 56) | (Get(data, 1) << 48) |
191 (Get(data, 2) << 40) | (Get(data, 3) << 32) | 354 (Get(data, 2) << 40) | (Get(data, 3) << 32) |
192 (Get(data, 4) << 24) | (Get(data, 5) << 16) | 355 (Get(data, 4) << 24) | (Get(data, 5) << 16) |
193 (Get(data, 6) << 8) | Get(data, 7); 356 (Get(data, 6) << 8) | Get(data, 7);
194 } 357 }
195 358
196 static T ReadLittleEndian(const uint8_t* data) { 359 static T ReadLittleEndian(const uint8_t* data) {
360 static_assert(sizeof(T) >= 8, kSizeErrorMsg);
197 return 361 return
198 Get(data, 0) | (Get(data, 1) << 8) | 362 Get(data, 0) | (Get(data, 1) << 8) |
199 (Get(data, 2) << 16) | (Get(data, 3) << 24) | 363 (Get(data, 2) << 16) | (Get(data, 3) << 24) |
200 (Get(data, 4) << 32) | (Get(data, 5) << 40) | 364 (Get(data, 4) << 32) | (Get(data, 5) << 40) |
201 (Get(data, 6) << 48) | (Get(data, 7) << 56); 365 (Get(data, 6) << 48) | (Get(data, 7) << 56);
202 } 366 }
203 367
204 private: 368 private:
205 inline static T Get(const uint8_t* data, unsigned int index) { 369 inline static T Get(const uint8_t* data, unsigned int index) {
206 return static_cast<T>(data[index]); 370 return static_cast<T>(data[index]);
207 } 371 }
208 }; 372 };
209 373
210 template<typename T> 374 template <typename T>
211 class ByteWriter<T, 8> { 375 class ByteWriter<T, 8, false> {
212 public: 376 public:
213 static void WriteBigEndian(uint8_t* data, T val) { 377 static void WriteBigEndian(uint8_t* data, T val) {
378 static_assert(sizeof(T) >= 8, kSizeErrorMsg);
214 data[0] = val >> 56; 379 data[0] = val >> 56;
215 data[1] = val >> 48; 380 data[1] = val >> 48;
216 data[2] = val >> 40; 381 data[2] = val >> 40;
217 data[3] = val >> 32; 382 data[3] = val >> 32;
218 data[4] = val >> 24; 383 data[4] = val >> 24;
219 data[5] = val >> 16; 384 data[5] = val >> 16;
220 data[6] = val >> 8; 385 data[6] = val >> 8;
221 data[7] = val; 386 data[7] = val;
222 } 387 }
223 388
224 static void WriteLittleEndian(uint8_t* data, T val) { 389 static void WriteLittleEndian(uint8_t* data, T val) {
390 static_assert(sizeof(T) >= 8, kSizeErrorMsg);
225 data[0] = val; 391 data[0] = val;
226 data[1] = val >> 8; 392 data[1] = val >> 8;
227 data[2] = val >> 16; 393 data[2] = val >> 16;
228 data[3] = val >> 24; 394 data[3] = val >> 24;
229 data[4] = val >> 32; 395 data[4] = val >> 32;
230 data[5] = val >> 40; 396 data[5] = val >> 40;
231 data[6] = val >> 48; 397 data[6] = val >> 48;
232 data[7] = val >> 56; 398 data[7] = val >> 56;
233 } 399 }
234 }; 400 };
235 401
236 } // namespace webrtc 402 } // namespace webrtc
237 403
238 #endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_BYTE_IO_H_ 404 #endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_BYTE_IO_H_
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698