Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/mozilla/WrappingOperations.h
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
/*
8
 * Math operations that implement wraparound semantics on overflow or underflow.
9
 *
10
 * While in some cases (but not all of them!) plain old C++ operators and casts
11
 * will behave just like these functions, there are three reasons you should use
12
 * these functions:
13
 *
14
 *   1) These functions make *explicit* the desire for and dependence upon
15
 *      wraparound semantics, just as Rust's i32::wrapping_add and similar
16
 *      functions explicitly produce wraparound in Rust.
17
 *   2) They implement this functionality *safely*, without invoking signed
18
 *      integer overflow that has undefined behavior in C++.
19
 *   3) They play nice with compiler-based integer-overflow sanitizers (see
20
 *      build/autoconf/sanitize.m4), that in appropriately configured builds
21
 *      verify at runtime that integral arithmetic doesn't overflow.
22
 */
23
24
#ifndef mozilla_WrappingOperations_h
25
#define mozilla_WrappingOperations_h
26
27
#include "mozilla/Attributes.h"
28
#include "mozilla/TypeTraits.h"
29
30
#include <limits.h>
31
32
namespace mozilla {
33
34
namespace detail {
35
36
template<typename UnsignedType>
37
struct WrapToSignedHelper
38
{
39
  static_assert(mozilla::IsUnsigned<UnsignedType>::value,
40
                "WrapToSigned must be passed an unsigned type");
41
42
  using SignedType = typename mozilla::MakeSigned<UnsignedType>::Type;
43
44
  static constexpr SignedType MaxValue =
45
    (UnsignedType(1) << (CHAR_BIT * sizeof(SignedType) - 1)) - 1;
46
  static constexpr SignedType MinValue = -MaxValue - 1;
47
48
  static constexpr UnsignedType MinValueUnsigned =
49
    static_cast<UnsignedType>(MinValue);
50
  static constexpr UnsignedType MaxValueUnsigned =
51
    static_cast<UnsignedType>(MaxValue);
52
53
  // Overflow-correctness was proven in bug 1432646 and is explained in the
54
  // comment below.  This function is very hot, both at compile time and
55
  // runtime, so disable all overflow checking in it.
56
  MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW MOZ_NO_SANITIZE_SIGNED_OVERFLOW
57
  static constexpr SignedType compute(UnsignedType aValue)
58
0
  {
59
0
    // This algorithm was originally provided here:
60
0
    // https://stackoverflow.com/questions/13150449/efficient-unsigned-to-signed-cast-avoiding-implementation-defined-behavior
61
0
    //
62
0
    // If the value is in the non-negative signed range, just cast.
63
0
    //
64
0
    // If the value will be negative, compute its delta from the first number
65
0
    // past the max signed integer, then add that to the minimum signed value.
66
0
    //
67
0
    // At the low end: if |u| is the maximum signed value plus one, then it has
68
0
    // the same mathematical value as |MinValue| cast to unsigned form.  The
69
0
    // delta is zero, so the signed form of |u| is |MinValue| -- exactly the
70
0
    // result of adding zero delta to |MinValue|.
71
0
    //
72
0
    // At the high end: if |u| is the maximum *unsigned* value, then it has all
73
0
    // bits set.  |MinValue| cast to unsigned form is purely the high bit set.
74
0
    // So the delta is all bits but high set -- exactly |MaxValue|.  And as
75
0
    // |MinValue = -MaxValue - 1|, we have |MaxValue + (-MaxValue - 1)| to
76
0
    // equal -1.
77
0
    //
78
0
    // Thus the delta below is in signed range, the corresponding cast is safe,
79
0
    // and this computation produces values spanning [MinValue, 0): exactly the
80
0
    // desired range of all negative signed integers.
81
0
    return (aValue <= MaxValueUnsigned)
82
0
           ? static_cast<SignedType>(aValue)
83
0
           : static_cast<SignedType>(aValue - MinValueUnsigned) + MinValue;
84
0
  }
Unexecuted instantiation: mozilla::detail::WrapToSignedHelper<unsigned long>::compute(unsigned long)
Unexecuted instantiation: mozilla::detail::WrapToSignedHelper<unsigned char>::compute(unsigned char)
Unexecuted instantiation: mozilla::detail::WrapToSignedHelper<unsigned short>::compute(unsigned short)
Unexecuted instantiation: mozilla::detail::WrapToSignedHelper<unsigned long long>::compute(unsigned long long)
85
};
86
87
} // namespace detail
88
89
/**
90
 * Convert an unsigned value to signed, if necessary wrapping around.
91
 *
92
 * This is the behavior normal C++ casting will perform in most implementations
93
 * these days -- but this function makes explicit that such conversion is
94
 * happening.
95
 */
96
template<typename UnsignedType>
97
constexpr typename detail::WrapToSignedHelper<UnsignedType>::SignedType
98
WrapToSigned(UnsignedType aValue)
99
0
{
100
0
  return detail::WrapToSignedHelper<UnsignedType>::compute(aValue);
101
0
}
Unexecuted instantiation: mozilla::detail::WrapToSignedHelper<unsigned long>::SignedType mozilla::WrapToSigned<unsigned long>(unsigned long)
Unexecuted instantiation: mozilla::detail::WrapToSignedHelper<unsigned char>::SignedType mozilla::WrapToSigned<unsigned char>(unsigned char)
Unexecuted instantiation: mozilla::detail::WrapToSignedHelper<unsigned short>::SignedType mozilla::WrapToSigned<unsigned short>(unsigned short)
Unexecuted instantiation: mozilla::detail::WrapToSignedHelper<unsigned long long>::SignedType mozilla::WrapToSigned<unsigned long long>(unsigned long long)
102
103
namespace detail {
104
105
template<typename T>
106
constexpr T
107
ToResult(typename MakeUnsigned<T>::Type aUnsigned)
108
593M
{
109
593M
  // We could *always* return WrapToSigned and rely on unsigned conversion to
110
593M
  // undo the wrapping when |T| is unsigned, but this seems clearer.
111
593M
  return IsSigned<T>::value ? WrapToSigned(aUnsigned) : aUnsigned;
112
593M
}
_ZN7mozilla6detail8ToResultIjEET_NS0_12MakeUnsignedIS2_NS_8RemoveCVIS2_E4TypeEXaasr10IsUnsignedIS6_EE5valuentsr6IsSameIcS6_EE5valueEE4TypeE
Line
Count
Source
108
593M
{
109
593M
  // We could *always* return WrapToSigned and rely on unsigned conversion to
110
593M
  // undo the wrapping when |T| is unsigned, but this seems clearer.
111
593M
  return IsSigned<T>::value ? WrapToSigned(aUnsigned) : aUnsigned;
112
593M
}
Unexecuted instantiation: _ZN7mozilla6detail8ToResultImEET_NS0_12MakeUnsignedIS2_NS_8RemoveCVIS2_E4TypeEXaasr10IsUnsignedIS6_EE5valuentsr6IsSameIcS6_EE5valueEE4TypeE
Unexecuted instantiation: _ZN7mozilla6detail8ToResultIiEET_NS0_12MakeUnsignedIS2_NS_8RemoveCVIS2_E4TypeEXaasr10IsUnsignedIS6_EE5valuentsr6IsSameIcS6_EE5valueEE4TypeE
113
114
template<typename T>
115
struct WrappingAddHelper
116
{
117
private:
118
  using UnsignedT = typename MakeUnsigned<T>::Type;
119
120
public:
121
  MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW
122
  static constexpr T compute(T aX, T aY)
123
0
  {
124
0
    return ToResult<T>(static_cast<UnsignedT>(aX) + static_cast<UnsignedT>(aY));
125
0
  }
126
};
127
128
} // namespace detail
129
130
/**
131
 * Add two integers of the same type and return the result converted to that
132
 * type using wraparound semantics, without triggering overflow sanitizers.
133
 *
134
 * For N-bit unsigned integer types, this is equivalent to adding the two
135
 * numbers, then taking the result mod 2**N:
136
 *
137
 *   WrappingAdd(uint32_t(42), uint32_t(17)) is 59 (59 mod 2**32);
138
 *   WrappingAdd(uint8_t(240), uint8_t(20)) is 4 (260 mod 2**8).
139
 *
140
 * Unsigned WrappingAdd acts exactly like C++ unsigned addition.
141
 *
142
 * For N-bit signed integer types, this is equivalent to adding the two numbers
143
 * wrapped to unsigned, then wrapping the sum mod 2**N to the signed range:
144
 *
145
 *   WrappingAdd(int16_t(32767), int16_t(3)) is -32766 ((32770 mod 2**16) - 2**16);
146
 *   WrappingAdd(int8_t(-128), int8_t(-128)) is 0 (256 mod 2**8);
147
 *   WrappingAdd(int32_t(-42), int32_t(-17)) is -59 ((8589934533 mod 2**32) - 2**32).
148
 *
149
 * There's no equivalent to this operation in C++, as C++ signed addition that
150
 * overflows has undefined behavior.  But it's how such addition *tends* to
151
 * behave with most compilers, unless an optimization or similar -- quite
152
 * permissibly -- triggers different behavior.
153
 */
154
template<typename T>
155
constexpr T
156
WrappingAdd(T aX, T aY)
157
0
{
158
0
  return detail::WrappingAddHelper<T>::compute(aX, aY);
159
0
}
160
161
namespace detail {
162
163
template<typename T>
164
struct WrappingSubtractHelper
165
{
166
private:
167
  using UnsignedT = typename MakeUnsigned<T>::Type;
168
169
public:
170
  MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW
171
  static constexpr T compute(T aX, T aY)
172
  {
173
    return ToResult<T>(static_cast<UnsignedT>(aX) - static_cast<UnsignedT>(aY));
174
  }
175
};
176
177
} // namespace detail
178
179
/**
180
 * Subtract two integers of the same type and return the result converted to
181
 * that type using wraparound semantics, without triggering overflow sanitizers.
182
 *
183
 * For N-bit unsigned integer types, this is equivalent to subtracting the two
184
 * numbers, then taking the result mod 2**N:
185
 *
186
 *   WrappingSubtract(uint32_t(42), uint32_t(17)) is 29 (29 mod 2**32);
187
 *   WrappingSubtract(uint8_t(5), uint8_t(20)) is 241 (-15 mod 2**8).
188
 *
189
 * Unsigned WrappingSubtract acts exactly like C++ unsigned subtraction.
190
 *
191
 * For N-bit signed integer types, this is equivalent to subtracting the two
192
 * numbers wrapped to unsigned, then wrapping the difference mod 2**N to the
193
 * signed range:
194
 *
195
 *   WrappingSubtract(int16_t(32767), int16_t(-5)) is -32764 ((32772 mod 2**16) - 2**16);
196
 *   WrappingSubtract(int8_t(-128), int8_t(127)) is 1 (-255 mod 2**8);
197
 *   WrappingSubtract(int32_t(-17), int32_t(-42)) is 25 (25 mod 2**32).
198
 *
199
 * There's no equivalent to this operation in C++, as C++ signed subtraction
200
 * that overflows has undefined behavior.  But it's how such subtraction *tends*
201
 * to behave with most compilers, unless an optimization or similar -- quite
202
 * permissibly -- triggers different behavior.
203
 */
204
template<typename T>
205
constexpr T
206
WrappingSubtract(T aX, T aY)
207
{
208
  return detail::WrappingSubtractHelper<T>::compute(aX, aY);
209
}
210
211
namespace detail {
212
213
template<typename T>
214
struct WrappingMultiplyHelper
215
{
216
private:
217
  using UnsignedT = typename MakeUnsigned<T>::Type;
218
219
public:
220
  MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW
221
  static constexpr T compute(T aX, T aY)
222
593M
  {
223
593M
    // Begin with |1U| to ensure the overall operation chain is never promoted
224
593M
    // to signed integer operations that might have *signed* integer overflow.
225
593M
    return ToResult<T>(static_cast<UnsignedT>(1U *
226
593M
                                              static_cast<UnsignedT>(aX) *
227
593M
                                              static_cast<UnsignedT>(aY)));
228
593M
  }
mozilla::detail::WrappingMultiplyHelper<unsigned int>::compute(unsigned int, unsigned int)
Line
Count
Source
222
593M
  {
223
593M
    // Begin with |1U| to ensure the overall operation chain is never promoted
224
593M
    // to signed integer operations that might have *signed* integer overflow.
225
593M
    return ToResult<T>(static_cast<UnsignedT>(1U *
226
593M
                                              static_cast<UnsignedT>(aX) *
227
593M
                                              static_cast<UnsignedT>(aY)));
228
593M
  }
Unexecuted instantiation: mozilla::detail::WrappingMultiplyHelper<int>::compute(int, int)
229
};
230
231
} // namespace detail
232
233
/**
234
 * Multiply two integers of the same type and return the result converted to
235
 * that type using wraparound semantics, without triggering overflow sanitizers.
236
 *
237
 * For N-bit unsigned integer types, this is equivalent to multiplying the two
238
 * numbers, then taking the result mod 2**N:
239
 *
240
 *   WrappingMultiply(uint32_t(42), uint32_t(17)) is 714 (714 mod 2**32);
241
 *   WrappingMultiply(uint8_t(16), uint8_t(24)) is 128 (384 mod 2**8);
242
 *   WrappingMultiply(uint16_t(3), uint16_t(32768)) is 32768 (98304 mod 2*16).
243
 *
244
 * Unsigned WrappingMultiply is *not* identical to C++ multiplication: with most
245
 * compilers, in rare cases uint16_t*uint16_t can invoke *signed* integer
246
 * overflow having undefined behavior!  http://kqueue.org/blog/2013/09/17/cltq/
247
 * has the grody details.  (Some compilers do this for uint32_t, not uint16_t.)
248
 * So it's especially important to use WrappingMultiply for wraparound math with
249
 * uint16_t.  That quirk aside, this function acts like you *thought* C++
250
 * unsigned multiplication always worked.
251
 *
252
 * For N-bit signed integer types, this is equivalent to multiplying the two
253
 * numbers wrapped to unsigned, then wrapping the product mod 2**N to the signed
254
 * range:
255
 *
256
 *   WrappingMultiply(int16_t(-456), int16_t(123)) is 9448 ((-56088 mod 2**16) + 2**16);
257
 *   WrappingMultiply(int32_t(-7), int32_t(-9)) is 63 (63 mod 2**32);
258
 *   WrappingMultiply(int8_t(16), int8_t(24)) is -128 ((384 mod 2**8) - 2**8);
259
 *   WrappingMultiply(int8_t(16), int8_t(255)) is -16 ((4080 mod 2**8) - 2**8).
260
 *
261
 * There's no equivalent to this operation in C++, as C++ signed
262
 * multiplication that overflows has undefined behavior.  But it's how such
263
 * multiplication *tends* to behave with most compilers, unless an optimization
264
 * or similar -- quite permissibly -- triggers different behavior.
265
 */
266
template<typename T>
267
constexpr T
268
WrappingMultiply(T aX, T aY)
269
593M
{
270
593M
  return detail::WrappingMultiplyHelper<T>::compute(aX, aY);
271
593M
}
unsigned int mozilla::WrappingMultiply<unsigned int>(unsigned int, unsigned int)
Line
Count
Source
269
593M
{
270
593M
  return detail::WrappingMultiplyHelper<T>::compute(aX, aY);
271
593M
}
Unexecuted instantiation: int mozilla::WrappingMultiply<int>(int, int)
272
273
// The |mozilla::Wrapping*| functions are constexpr. Unfortunately, MSVC warns
274
// about well-defined unsigned integer overflows that may occur within the
275
// constexpr math.
276
//
277
//   https://msdn.microsoft.com/en-us/library/4kze989h.aspx (C4307)
278
//   https://developercommunity.visualstudio.com/content/problem/211134/unsigned-integer-overflows-in-constexpr-functionsa.html (bug report)
279
//
280
// So we need a way to suppress these warnings. Unfortunately, the warnings are
281
// issued at the very top of the `constexpr` chain, which is often some
282
// distance from the triggering Wrapping*() operation. So we can't suppress
283
// them within this file. Instead, callers have to do it with these macros.
284
//
285
// If/when MSVC fix this bug, we should remove these macros.
286
#ifdef _MSC_VER
287
#define MOZ_PUSH_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING \
288
  __pragma(warning(push)) \
289
  __pragma(warning(disable:4307))
290
#define MOZ_POP_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING \
291
  __pragma(warning(pop))
292
#else
293
#define MOZ_PUSH_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
294
#define MOZ_POP_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
295
#endif
296
297
} /* namespace mozilla */
298
299
#endif /* mozilla_WrappingOperations_h */