1#include "dng_safe_arithmetic.h"
2
3#include <cmath>
4#include <limits>
5
6#include "dng_exceptions.h"
7
8// Implementation of safe integer arithmetic follows guidelines from
9// https://www.securecoding.cert.org/confluence/display/c/INT30-C.+Ensure+that+unsigned+integer+operations+do+not+wrap
10// and
11// https://www.securecoding.cert.org/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow
12
13namespace {
14
15// Template functions for safe arithmetic. These functions are not exposed in
16// the header for the time being to avoid having to add checks for the various
17// constraints on the template argument (e.g. that it is integral and possibly
18// signed or unsigned only). This should be done using a static_assert(), but
19// we want to be portable to pre-C++11 compilers.
20
21// Returns the result of adding arg1 and arg2 if it will fit in a T (where T is
22// a signed or unsigned integer type). Otherwise, throws a dng_exception with
23// error code dng_error_unknown.
24template <class T>
25T SafeAdd(T arg1, T arg2) {
26  // The condition is reformulated relative to the version on
27  // www.securecoding.cert.org to check for valid instead of invalid cases. It
28  // seems safer to enumerate the valid cases (and potentially miss one) than
29  // enumerate the invalid cases.
30  // If T is an unsigned type, the second half of the condition always evaluates
31  // to false and will presumably be compiled out by the compiler.
32  if ((arg1 >= 0 && arg2 <= std::numeric_limits<T>::max() - arg1) ||
33      (arg1 < 0 && arg2 >= std::numeric_limits<T>::min() - arg1)) {
34    return arg1 + arg2;
35  } else {
36    ThrowProgramError("Arithmetic overflow");
37    abort();  // Never reached.
38  }
39}
40
41// Returns the result of multiplying arg1 and arg2 if it will fit in a T (where
42// T is an unsigned integer type). Otherwise, throws a dng_exception with error
43// code dng_error_unknown.
44template <class T>
45T SafeUnsignedMult(T arg1, T arg2) {
46  if (arg1 == 0 || arg2 <= std::numeric_limits<T>::max() / arg1) {
47    return arg1 * arg2;
48  } else {
49    ThrowProgramError("Arithmetic overflow");
50    abort();  // Never reached.
51  }
52}
53
54}  // namespace
55
56bool SafeInt32Add(std::int32_t arg1, std::int32_t arg2, std::int32_t *result) {
57  try {
58    *result = SafeInt32Add(arg1, arg2);
59    return true;
60  } catch (const dng_exception &) {
61    return false;
62  }
63}
64
65std::int32_t SafeInt32Add(std::int32_t arg1, std::int32_t arg2) {
66  return SafeAdd<std::int32_t>(arg1, arg2);
67}
68
69std::int64_t SafeInt64Add(std::int64_t arg1, std::int64_t arg2) {
70  return SafeAdd<std::int64_t>(arg1, arg2);
71}
72
73bool SafeUint32Add(std::uint32_t arg1, std::uint32_t arg2,
74                   std::uint32_t *result) {
75  try {
76    *result = SafeUint32Add(arg1, arg2);
77    return true;
78  } catch (const dng_exception &) {
79    return false;
80  }
81}
82
83std::uint32_t SafeUint32Add(std::uint32_t arg1, std::uint32_t arg2) {
84  return SafeAdd<std::uint32_t>(arg1, arg2);
85}
86
87std::uint64_t SafeUint64Add(std::uint64_t arg1, std::uint64_t arg2) {
88  return SafeAdd<std::uint64_t>(arg1, arg2);
89}
90
91bool SafeInt32Sub(std::int32_t arg1, std::int32_t arg2, std::int32_t *result) {
92  if ((arg2 >= 0 && arg1 >= std::numeric_limits<int32_t>::min() + arg2) ||
93      (arg2 < 0 && arg1 <= std::numeric_limits<int32_t>::max() + arg2)) {
94    *result = arg1 - arg2;
95    return true;
96  } else {
97    return false;
98  }
99}
100
101std::int32_t SafeInt32Sub(std::int32_t arg1, std::int32_t arg2) {
102  std::int32_t result = 0;
103
104  if (!SafeInt32Sub(arg1, arg2, &result)) {
105    ThrowProgramError("Arithmetic overflow");
106  }
107
108  return result;
109}
110
111std::uint32_t SafeUint32Sub(std::uint32_t arg1, std::uint32_t arg2) {
112  if (arg1 >= arg2) {
113    return arg1 - arg2;
114  } else {
115    ThrowProgramError("Arithmetic overflow");
116    abort();  // Never reached.
117  }
118}
119
120bool SafeUint32Mult(std::uint32_t arg1, std::uint32_t arg2,
121                    std::uint32_t *result) {
122  try {
123    *result = SafeUint32Mult(arg1, arg2);
124    return true;
125  } catch (const dng_exception &) {
126    return false;
127  }
128}
129
130bool SafeUint32Mult(std::uint32_t arg1, std::uint32_t arg2, std::uint32_t arg3,
131                    std::uint32_t *result) {
132  try {
133    *result = SafeUint32Mult(arg1, arg2, arg3);
134    return true;
135  } catch (const dng_exception &) {
136    return false;
137  }
138}
139
140bool SafeUint32Mult(std::uint32_t arg1, std::uint32_t arg2, std::uint32_t arg3,
141                    std::uint32_t arg4, std::uint32_t *result) {
142  try {
143    *result = SafeUint32Mult(arg1, arg2, arg3, arg4);
144    return true;
145  } catch (const dng_exception &) {
146    return false;
147  }
148}
149
150std::uint32_t SafeUint32Mult(std::uint32_t arg1, std::uint32_t arg2) {
151  return SafeUnsignedMult<std::uint32_t>(arg1, arg2);
152}
153
154std::uint32_t SafeUint32Mult(std::uint32_t arg1, std::uint32_t arg2,
155                             std::uint32_t arg3) {
156  return SafeUint32Mult(SafeUint32Mult(arg1, arg2), arg3);
157}
158
159std::uint32_t SafeUint32Mult(std::uint32_t arg1, std::uint32_t arg2,
160                             std::uint32_t arg3, std::uint32_t arg4) {
161  return SafeUint32Mult(SafeUint32Mult(arg1, arg2, arg3), arg4);
162}
163
164std::int32_t SafeInt32Mult(std::int32_t arg1, std::int32_t arg2) {
165  const std::int64_t tmp =
166      static_cast<std::int64_t>(arg1) * static_cast<std::int64_t>(arg2);
167  if (tmp >= std::numeric_limits<std::int32_t>::min() &&
168      tmp <= std::numeric_limits<std::int32_t>::max()) {
169    return static_cast<std::int32_t>(tmp);
170  } else {
171    ThrowProgramError("Arithmetic overflow");
172    abort();
173  }
174}
175
176std::size_t SafeSizetMult(std::size_t arg1, std::size_t arg2) {
177  return SafeUnsignedMult<std::size_t>(arg1, arg2);
178}
179
180namespace dng_internal {
181
182std::int64_t SafeInt64MultSlow(std::int64_t arg1, std::int64_t arg2) {
183  bool overflow = true;
184
185  if (arg1 > 0) {
186    if (arg2 > 0) {
187      overflow = (arg1 > std::numeric_limits<std::int64_t>::max() / arg2);
188    } else {
189      overflow = (arg2 < std::numeric_limits<std::int64_t>::min() / arg1);
190    }
191  } else {
192    if (arg2 > 0) {
193      overflow = (arg1 < std::numeric_limits<std::int64_t>::min() / arg2);
194    } else {
195      overflow = (arg1 != 0 &&
196                  arg2 < std::numeric_limits<std::int64_t>::max() / arg1);
197    }
198  }
199
200  if (overflow) {
201    ThrowProgramError("Arithmetic overflow");
202    abort();  // Never reached.
203  } else {
204    return arg1 * arg2;
205  }
206}
207
208}  // namespace dng_internal
209
210std::uint32_t SafeUint32DivideUp(std::uint32_t arg1, std::uint32_t arg2) {
211  // It might seem more intuitive to implement this function simply as
212  //
213  //   return arg2 == 0 ? 0 : (arg1 + arg2 - 1) / arg2;
214  //
215  // but the expression "arg1 + arg2" can wrap around.
216
217  if (arg2 == 0) {
218    ThrowProgramError("Division by zero");
219    abort();  // Never reached.
220  } else if (arg1 == 0) {
221    // If arg1 is zero, return zero to avoid wraparound in the expression
222    //   "arg1 - 1" below.
223    return 0;
224  } else {
225    return (arg1 - 1) / arg2 + 1;
226  }
227}
228
229bool RoundUpUint32ToMultiple(std::uint32_t val, std::uint32_t multiple_of,
230                             std::uint32_t *result) {
231  try {
232    *result = RoundUpUint32ToMultiple(val, multiple_of);
233    return true;
234  } catch (const dng_exception &) {
235    return false;
236  }
237}
238
239std::uint32_t RoundUpUint32ToMultiple(std::uint32_t val,
240                                      std::uint32_t multiple_of) {
241  if (multiple_of == 0) {
242    ThrowProgramError("multiple_of is zero in RoundUpUint32ToMultiple");
243  }
244
245  const std::uint32_t remainder = val % multiple_of;
246  if (remainder == 0) {
247    return val;
248  } else {
249    return SafeUint32Add(val, multiple_of - remainder);
250  }
251}
252
253bool ConvertUint32ToInt32(std::uint32_t val, std::int32_t *result) {
254  try {
255    *result = ConvertUint32ToInt32(val);
256    return true;
257  } catch (const dng_exception &) {
258    return false;
259  }
260}
261
262std::int32_t ConvertUint32ToInt32(std::uint32_t val) {
263  const std::uint32_t kInt32MaxAsUint32 =
264      static_cast<std::uint32_t>(std::numeric_limits<std::int32_t>::max());
265
266  if (val <= kInt32MaxAsUint32) {
267    return static_cast<std::int32_t>(val);
268  } else {
269    ThrowProgramError("Arithmetic overflow");
270    abort();  // Never reached.
271  }
272}
273
274std::int32_t ConvertDoubleToInt32(double val) {
275  const double kMin =
276      static_cast<double>(std::numeric_limits<std::int32_t>::min());
277  const double kMax =
278      static_cast<double>(std::numeric_limits<std::int32_t>::max());
279  // NaNs will fail this test; they always compare false.
280  if (val > kMin - 1.0 && val < kMax + 1.0) {
281    return static_cast<std::int32_t>(val);
282  } else {
283    ThrowProgramError("Argument not in range in ConvertDoubleToInt32");
284    abort();  // Never reached.
285  }
286}
287
288std::uint32_t ConvertDoubleToUint32(double val) {
289  const double kMax =
290      static_cast<double>(std::numeric_limits<std::uint32_t>::max());
291  // NaNs will fail this test; they always compare false.
292  if (val >= 0.0 && val < kMax + 1.0) {
293    return static_cast<std::uint32_t>(val);
294  } else {
295    ThrowProgramError("Argument not in range in ConvertDoubleToUint32");
296    abort();  // Never reached.
297  }
298}
299
300float ConvertDoubleToFloat(double val) {
301  const double kMax = std::numeric_limits<float>::max();
302  if (val > kMax) {
303    return std::numeric_limits<float>::infinity();
304  } else if (val < -kMax) {
305    return -std::numeric_limits<float>::infinity();
306  } else {
307    // The cases that end up here are:
308    // - values in [-kMax, kMax]
309    // - NaN (because it always compares false)
310    return static_cast<float>(val);
311  }
312}
313