1 /*****************************************************************************/
2 // Copyright 2015-2019 Adobe Systems Incorporated
3 // All Rights Reserved.
4 //
5 // NOTICE: Adobe permits you to use, modify, and distribute this file in
6 // accordance with the terms of the Adobe license agreement accompanying it.
7 /*****************************************************************************/
8
9 #include "dng_safe_arithmetic.h"
10
11 #include <limits>
12
13 #include "dng_exceptions.h"
14
15 // Implementation of safe integer arithmetic follows guidelines from
16 // https://www.securecoding.cert.org/confluence/display/c/INT30-C.+Ensure+that+unsigned+integer+operations+do+not+wrap
17 // and
18 // https://www.securecoding.cert.org/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow
19
20 namespace {
21
22 // Template functions for safe arithmetic. These functions are not exposed in
23 // the header for the time being to avoid having to add checks for the various
24 // constraints on the template argument (e.g. that it is integral and possibly
25 // signed or unsigned only). This should be done using a static_assert(), but
26 // we want to be portable to pre-C++11 compilers.
27
28 // Returns the result of adding arg1 and arg2 if it will fit in a T (where T is
29 // a signed or unsigned integer type). Otherwise, throws a dng_exception with
30 // error code dng_error_unknown.
31 template <class T>
SafeAdd(T arg1,T arg2)32 T SafeAdd(T arg1, T arg2) {
33 // The condition is reformulated relative to the version on
34 // www.securecoding.cert.org to check for valid instead of invalid cases. It
35 // seems safer to enumerate the valid cases (and potentially miss one) than
36 // enumerate the invalid cases.
37 // If T is an unsigned type, the second half of the condition always evaluates
38 // to false and will presumably be compiled out by the compiler.
39 if ((arg1 >= 0 && arg2 <= std::numeric_limits<T>::max() - arg1) ||
40 (arg1 < 0 && arg2 >= std::numeric_limits<T>::min() - arg1)) {
41 return arg1 + arg2;
42 } else {
43 ThrowOverflow ("Arithmetic overflow in SafeAdd");
44
45 // Dummy return statement.
46 return 0;
47 }
48 }
49
50 // Returns the result of multiplying arg1 and arg2 if it will fit in a T (where
51 // T is an unsigned integer type). Otherwise, throws a dng_exception with error
52 // code dng_error_unknown.
53 template <class T>
SafeUnsignedMult(T arg1,T arg2)54 T SafeUnsignedMult(T arg1, T arg2) {
55 if (arg1 == 0 || arg2 <= std::numeric_limits<T>::max() / arg1) {
56 return arg1 * arg2;
57 } else {
58 ThrowOverflow ("Arithmetic overflow in SafeUnsignedMult");
59
60 // Dummy return statement.
61 return 0;
62 }
63 }
64
65 } // namespace
66
SafeInt32Add(int32 arg1,int32 arg2,int32 * result)67 bool SafeInt32Add(int32 arg1, int32 arg2, int32 *result) {
68 try {
69 *result = SafeInt32Add(arg1, arg2);
70 return true;
71 } catch (const dng_exception &) {
72 return false;
73 }
74 }
75
SafeInt32Add(int32 arg1,int32 arg2)76 int32 SafeInt32Add(int32 arg1, int32 arg2) {
77 return SafeAdd<int32>(arg1, arg2);
78 }
79
SafeInt64Add(int64 arg1,int64 arg2)80 int64 SafeInt64Add(int64 arg1, int64 arg2) {
81 return SafeAdd<int64>(arg1, arg2);
82 }
83
SafeUint32Add(uint32 arg1,uint32 arg2,uint32 * result)84 bool SafeUint32Add(uint32 arg1, uint32 arg2,
85 uint32 *result) {
86 try {
87 *result = SafeUint32Add(arg1, arg2);
88 return true;
89 } catch (const dng_exception &) {
90 return false;
91 }
92 }
93
SafeUint32Add(uint32 arg1,uint32 arg2)94 uint32 SafeUint32Add(uint32 arg1, uint32 arg2) {
95 return SafeAdd<uint32>(arg1, arg2);
96 }
97
SafeInt32Sub(int32 arg1,int32 arg2,int32 * result)98 bool SafeInt32Sub(int32 arg1, int32 arg2, int32 *result) {
99 if ((arg2 >= 0 && arg1 >= std::numeric_limits<int32_t>::min() + arg2) ||
100 (arg2 < 0 && arg1 <= std::numeric_limits<int32_t>::max() + arg2)) {
101 *result = arg1 - arg2;
102 return true;
103 } else {
104 return false;
105 }
106 }
107
SafeInt32Sub(int32 arg1,int32 arg2)108 int32 SafeInt32Sub(int32 arg1, int32 arg2) {
109 int32 result = 0;
110
111 if (!SafeInt32Sub(arg1, arg2, &result)) {
112 ThrowOverflow ("Arithmetic overflow in SafeInt32Sub");
113 }
114
115 return result;
116 }
117
SafeUint32Mult(uint32 arg1,uint32 arg2,uint32 * result)118 bool SafeUint32Mult(uint32 arg1, uint32 arg2,
119 uint32 *result) {
120 try {
121 *result = SafeUint32Mult(arg1, arg2);
122 return true;
123 } catch (const dng_exception &) {
124 return false;
125 }
126 }
127
SafeUint32Mult(uint32 arg1,uint32 arg2,uint32 arg3,uint32 * result)128 bool SafeUint32Mult(uint32 arg1, uint32 arg2, uint32 arg3,
129 uint32 *result) {
130 try {
131 *result = SafeUint32Mult(arg1, arg2, arg3);
132 return true;
133 } catch (const dng_exception &) {
134 return false;
135 }
136 }
137
SafeUint32Mult(uint32 arg1,uint32 arg2,uint32 arg3,uint32 arg4,uint32 * result)138 bool SafeUint32Mult(uint32 arg1, uint32 arg2, uint32 arg3,
139 uint32 arg4, uint32 *result) {
140 try {
141 *result = SafeUint32Mult(arg1, arg2, arg3, arg4);
142 return true;
143 } catch (const dng_exception &) {
144 return false;
145 }
146 }
147
SafeUint32Mult(uint32 arg1,uint32 arg2)148 uint32 SafeUint32Mult(uint32 arg1, uint32 arg2) {
149 return SafeUnsignedMult<uint32>(arg1, arg2);
150 }
151
SafeUint32Mult(uint32 arg1,uint32 arg2,uint32 arg3)152 uint32 SafeUint32Mult(uint32 arg1, uint32 arg2,
153 uint32 arg3) {
154 return SafeUint32Mult(SafeUint32Mult(arg1, arg2), arg3);
155 }
156
SafeUint32Mult(uint32 arg1,uint32 arg2,uint32 arg3,uint32 arg4)157 uint32 SafeUint32Mult(uint32 arg1, uint32 arg2,
158 uint32 arg3, uint32 arg4) {
159 return SafeUint32Mult(SafeUint32Mult(arg1, arg2, arg3), arg4);
160 }
161
SafeSizetMult(std::size_t arg1,std::size_t arg2)162 std::size_t SafeSizetMult(std::size_t arg1, std::size_t arg2) {
163 return SafeUnsignedMult<std::size_t>(arg1, arg2);
164 }
165
SafeInt64Mult(int64 arg1,int64 arg2)166 int64 SafeInt64Mult(int64 arg1, int64 arg2) {
167 bool overflow = true;
168
169 if (arg1 > 0) {
170 if (arg2 > 0) {
171 overflow = (arg1 > INT64_MAX / arg2);
172 } else {
173 overflow = (arg2 < INT64_MIN / arg1);
174 }
175 } else {
176 if (arg2 > 0) {
177 overflow = (arg1 < INT64_MIN / arg2);
178 } else {
179 overflow = (arg1 != 0 && arg2 < INT64_MAX / arg1);
180 }
181 }
182
183 if (overflow) {
184 ThrowOverflow ("Arithmetic overflow");
185
186 // Dummy return.
187 return 0;
188 } else {
189 return arg1 * arg2;
190 }
191 }
192
SafeUint32DivideUp(uint32 arg1,uint32 arg2)193 uint32 SafeUint32DivideUp(uint32 arg1, uint32 arg2) {
194 // It might seem more intuitive to implement this function simply as
195 //
196 // return arg2 == 0 ? 0 : (arg1 + arg2 - 1) / arg2;
197 //
198 // but the expression "arg1 + arg2" can wrap around.
199
200 if (arg2 == 0) {
201 ThrowProgramError("Division by zero");
202
203 // Dummy return to avoid compiler error about missing return statement.
204 return 0;
205 } else if (arg1 == 0) {
206 // If arg1 is zero, return zero to avoid wraparound in the expression
207 // "arg1 - 1" below.
208 return 0;
209 } else {
210 return (arg1 - 1) / arg2 + 1;
211 }
212 }
213
RoundUpUint32ToMultiple(uint32 val,uint32 multiple_of,uint32 * result)214 bool RoundUpUint32ToMultiple(uint32 val, uint32 multiple_of,
215 uint32 *result) {
216 if (multiple_of == 0) {
217 return false;
218 }
219
220 const uint32 remainder = val % multiple_of;
221 if (remainder == 0) {
222 *result = val;
223 return true;
224 } else {
225 return SafeUint32Add(val, multiple_of - remainder, result);
226 }
227 }
228
ConvertUint32ToInt32(uint32 val,int32 * result)229 bool ConvertUint32ToInt32(uint32 val, int32 *result) {
230 const uint32 kInt32MaxAsUint32 =
231 static_cast<uint32>(std::numeric_limits<int32>::max());
232
233 if (val <= kInt32MaxAsUint32) {
234 *result = static_cast<int32>(val);
235 return true;
236 } else {
237 return false;
238 }
239 }
240
241 /*****************************************************************************/
242
dng_safe_uint32(const dng_safe_int32 & x)243 dng_safe_uint32::dng_safe_uint32 (const dng_safe_int32 &x)
244 {
245
246 if (x.Get () < 0)
247 {
248 ThrowOverflow ("Overflow in dng_safe_uint32");
249 }
250
251 fValue = static_cast<uint32> (x.Get ());
252
253 }
254
255 /*****************************************************************************/
256
dng_safe_int32(const dng_safe_uint32 & x)257 dng_safe_int32::dng_safe_int32 (const dng_safe_uint32 &x)
258 {
259
260 Set_uint32 (x.Get ());
261
262 }
263
264 /*****************************************************************************/
265