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