• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* ***** BEGIN LICENSE BLOCK *****
4  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5  *
6  * The contents of this file are subject to the Mozilla Public License Version
7  * 1.1 (the "License"); you may not use this file except in compliance with
8  * the License. You may obtain a copy of the License at
9  * http://www.mozilla.org/MPL/
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the
14  * License.
15  *
16  * The Original Code is Mozilla code.
17  *
18  * The Initial Developer of the Original Code is the Mozilla Corporation.
19  * Portions created by the Initial Developer are Copyright (C) 2009
20  * the Initial Developer. All Rights Reserved.
21  *
22  * Contributor(s):
23  *  Benoit Jacob <bjacob@mozilla.com>
24  *  Jeff Muizelaar <jmuizelaar@mozilla.com>
25  *
26  * Alternatively, the contents of this file may be used under the terms of
27  * either the GNU General Public License Version 2 or later (the "GPL"), or
28  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29  * in which case the provisions of the GPL or the LGPL are applicable instead
30  * of those above. If you wish to allow use of your version of this file only
31  * under the terms of either the GPL or the LGPL, and not to allow others to
32  * use your version of this file under the terms of the MPL, indicate your
33  * decision by deleting the provisions above and replace them with the notice
34  * and other provisions required by the GPL or the LGPL. If you do not delete
35  * the provisions above, a recipient may use your version of this file under
36  * the terms of any one of the MPL, the GPL or the LGPL.
37  *
38  * ***** END LICENSE BLOCK ***** */
39 
40 // Necessary modifications are made to the original CheckedInt.h file to remove
41 // dependencies on prtypes.
42 // Also, change define Mozilla_CheckedInt_h to CheckedInt_h, change namespace
43 // from mozilla to WebCore for easier usage.
44 
45 #ifndef CheckedInt_h
46 #define CheckedInt_h
47 
48 #include <climits>
49 
50 namespace WebCore {
51 
52 namespace CheckedInt_internal {
53 
54 /* we don't want to use std::numeric_limits here because int... types may not support it,
55  * depending on the platform, e.g. on certain platform they use nonstandard built-in types
56  */
57 
58 /*** Step 1: manually record information for all the types that we want to support
59  ***/
60 
61 struct unsupported_type {};
62 
63 template<typename T> struct integer_type_manually_recorded_info;
64 
65 
66 #define CHECKEDINT_REGISTER_SUPPORTED_TYPE(T,_twice_bigger_type,_unsigned_type) \
67 template<> struct integer_type_manually_recorded_info<T>       \
68 {                                                              \
69     enum { is_supported = 1 };                                 \
70     typedef _twice_bigger_type twice_bigger_type;              \
71     typedef _unsigned_type unsigned_type;                      \
72 };
73 
74 //                                 Type      Twice Bigger Type   Unsigned Type
75 CHECKEDINT_REGISTER_SUPPORTED_TYPE(int8_t,   int16_t,             uint8_t)
76 CHECKEDINT_REGISTER_SUPPORTED_TYPE(uint8_t,  uint16_t,            uint8_t)
77 CHECKEDINT_REGISTER_SUPPORTED_TYPE(int16_t,  int32_t,             uint16_t)
78 CHECKEDINT_REGISTER_SUPPORTED_TYPE(uint16_t, uint32_t,            uint16_t)
79 CHECKEDINT_REGISTER_SUPPORTED_TYPE(int32_t,  int64_t,             uint32_t)
80 CHECKEDINT_REGISTER_SUPPORTED_TYPE(uint32_t, uint64_t,            uint32_t)
81 CHECKEDINT_REGISTER_SUPPORTED_TYPE(int64_t,  unsupported_type,    uint64_t)
82 CHECKEDINT_REGISTER_SUPPORTED_TYPE(uint64_t, unsupported_type,    uint64_t)
83 
84 // now implement the fallback for standard types like int, long, ...
85 // the difficulty is that they may or may not be equal to one of the above types, and/or
86 // to each other. This is why any attempt to handle at once PRInt8... types and standard types
87 // is bound to fail.
88 template<typename T>
89 struct is_standard_integer_type { enum { value = 0 }; };
90 
91 template<>
92 struct is_standard_integer_type<char> { enum { value = 1 }; };
93 template<>
94 struct is_standard_integer_type<unsigned char> { enum { value = 1 }; };
95 template<>
96 struct is_standard_integer_type<short> { enum { value = 1 }; };
97 template<>
98 struct is_standard_integer_type<unsigned short> { enum { value = 1 }; };
99 template<>
100 struct is_standard_integer_type<int> { enum { value = 1 }; };
101 template<>
102 struct is_standard_integer_type<unsigned int> { enum { value = 1 }; };
103 template<>
104 struct is_standard_integer_type<long> { enum { value = 1 }; };
105 template<>
106 struct is_standard_integer_type<unsigned long> { enum { value = 1 }; };
107 template<>
108 struct is_standard_integer_type<long long> { enum { value = 1 }; };
109 template<>
110 struct is_standard_integer_type<unsigned long long> { enum { value = 1 }; };
111 
112 template<int size, bool is_signed>
113 struct explicitly_sized_integer_type {};
114 
115 template<>
116 struct explicitly_sized_integer_type<1, true> { typedef int8_t type; };
117 template<>
118 struct explicitly_sized_integer_type<1, false> { typedef uint8_t type; };
119 template<>
120 struct explicitly_sized_integer_type<2, true> { typedef int16_t type; };
121 template<>
122 struct explicitly_sized_integer_type<2, false> { typedef uint16_t type; };
123 template<>
124 struct explicitly_sized_integer_type<4, true> { typedef int32_t type; };
125 template<>
126 struct explicitly_sized_integer_type<4, false> { typedef uint32_t type; };
127 template<>
128 struct explicitly_sized_integer_type<8, true> { typedef int64_t type; };
129 template<>
130 struct explicitly_sized_integer_type<8, false> { typedef uint64_t type; };
131 
132 template<typename T> struct integer_type_manually_recorded_info
133 {
134     enum {
135       is_supported = is_standard_integer_type<T>::value,
136       size = sizeof(T),
137       is_signed = (T(-1) > T(0)) ? 0 : 1
138     };
139     typedef typename explicitly_sized_integer_type<size, is_signed>::type explicit_sized_type;
140     typedef integer_type_manually_recorded_info<explicit_sized_type> base;
141     typedef typename base::twice_bigger_type twice_bigger_type;
142     typedef typename base::unsigned_type unsigned_type;
143 };
144 
145 template<typename T, bool is_supported = integer_type_manually_recorded_info<T>::is_supported>
146 struct TYPE_NOT_SUPPORTED_BY_CheckedInt {};
147 
148 template<typename T>
149 struct TYPE_NOT_SUPPORTED_BY_CheckedInt<T, true> { static void run() {} };
150 
151 
152 /*** Step 2: record some info about a given integer type,
153  ***         including whether it is supported, whether a twice bigger integer type
154  ***         is supported, what that twice bigger type is, and some stuff as found
155  ***         in std::numeric_limits (which we don't use because int.. types may
156  ***         not support it, if they are defined directly from compiler built-in types).
157  ***/
158 
159 template<typename T> struct is_unsupported_type { enum { answer = 0 }; };
160 template<> struct is_unsupported_type<unsupported_type> { enum { answer = 1 }; };
161 
162 template<typename T> struct integer_traits
163 {
164     typedef typename integer_type_manually_recorded_info<T>::twice_bigger_type twice_bigger_type;
165 
166     enum {
167         is_supported = integer_type_manually_recorded_info<T>::is_supported,
168         twice_bigger_type_is_supported
169             = is_unsupported_type<
170                   typename integer_type_manually_recorded_info<T>::twice_bigger_type
171               >::answer ? 0 : 1,
172         size = sizeof(T),
173         position_of_sign_bit = CHAR_BIT * size - 1,
174         is_signed = (T(-1) > T(0)) ? 0 : 1
175     };
176 
177     static T min()
178     {
179         // bitwise ops may return a larger type, that's why we cast explicitly to T
180         return is_signed ? T(T(1) << position_of_sign_bit) : T(0);
181     }
182 
183     static T max()
184     {
185         return ~min();
186     }
187 };
188 
189 /*** Step 3: Implement the actual validity checks --- ideas taken from IntegerLib, code different.
190  ***/
191 
192 // bitwise ops may return a larger type, so it's good to use these inline helpers guaranteeing that
193 // the result is really of type T
194 
195 template<typename T> inline T has_sign_bit(T x)
196 {
197     return x >> integer_traits<T>::position_of_sign_bit;
198 }
199 
200 template<typename T> inline T binary_complement(T x)
201 {
202     return ~x;
203 }
204 
205 template<typename T, typename U,
206          bool is_T_signed = integer_traits<T>::is_signed,
207          bool is_U_signed = integer_traits<U>::is_signed>
208 struct is_in_range_impl {};
209 
210 template<typename T, typename U>
211 struct is_in_range_impl<T, U, true, true>
212 {
213     static T run(U x)
214     {
215         return (x <= integer_traits<T>::max()) &
216                (x >= integer_traits<T>::min());
217     }
218 };
219 
220 template<typename T, typename U>
221 struct is_in_range_impl<T, U, false, false>
222 {
223     static T run(U x)
224     {
225         return x <= integer_traits<T>::max();
226     }
227 };
228 
229 template<typename T, typename U>
230 struct is_in_range_impl<T, U, true, false>
231 {
232     static T run(U x)
233     {
234         if (sizeof(T) > sizeof(U))
235             return 1;
236         else
237             return x <= U(integer_traits<T>::max());
238     }
239 };
240 
241 template<typename T, typename U>
242 struct is_in_range_impl<T, U, false, true>
243 {
244     static T run(U x)
245     {
246         if (sizeof(T) >= sizeof(U))
247             return x >= 0;
248         else
249             return x >= 0 && x <= U(integer_traits<T>::max());
250     }
251 };
252 
253 template<typename T, typename U> inline T is_in_range(U x)
254 {
255     return is_in_range_impl<T, U>::run(x);
256 }
257 
258 template<typename T> inline T is_add_valid(T x, T y, T result)
259 {
260     return integer_traits<T>::is_signed ?
261                         // addition is valid if the sign of x+y is equal to either that of x or that of y.
262                         // Beware! These bitwise operations can return a larger integer type, if T was a
263                         // small type like int8, so we explicitly cast to T.
264                         has_sign_bit(binary_complement(T((result^x) & (result^y))))
265                     :
266                         binary_complement(x) >= y;
267 }
268 
269 template<typename T> inline T is_sub_valid(T x, T y, T result)
270 {
271     return integer_traits<T>::is_signed ?
272                         // substraction is valid if either x and y have same sign, or x-y and x have same sign
273                         has_sign_bit(binary_complement(T((result^x) & (x^y))))
274                     :
275                         x >= y;
276 }
277 
278 template<typename T,
279          bool is_signed =  integer_traits<T>::is_signed,
280          bool twice_bigger_type_is_supported = integer_traits<T>::twice_bigger_type_is_supported>
281 struct is_mul_valid_impl {};
282 
283 template<typename T>
284 struct is_mul_valid_impl<T, true, true>
285 {
286     static T run(T x, T y)
287     {
288         typedef typename integer_traits<T>::twice_bigger_type twice_bigger_type;
289         twice_bigger_type product = twice_bigger_type(x) * twice_bigger_type(y);
290         return is_in_range<T>(product);
291     }
292 };
293 
294 template<typename T>
295 struct is_mul_valid_impl<T, false, true>
296 {
297     static T run(T x, T y)
298     {
299         typedef typename integer_traits<T>::twice_bigger_type twice_bigger_type;
300         twice_bigger_type product = twice_bigger_type(x) * twice_bigger_type(y);
301         return is_in_range<T>(product);
302     }
303 };
304 
305 template<typename T>
306 struct is_mul_valid_impl<T, true, false>
307 {
308     static T run(T x, T y)
309     {
310         const T max_value = integer_traits<T>::max();
311         const T min_value = integer_traits<T>::min();
312 
313         if (x == 0 || y == 0) return true;
314 
315         if (x > 0) {
316             if (y > 0)
317                 return x <= max_value / y;
318             else
319                 return y >= min_value / x;
320         } else {
321             if (y > 0)
322                 return x >= min_value / y;
323             else
324                 return y >= max_value / x;
325         }
326     }
327 };
328 
329 template<typename T>
330 struct is_mul_valid_impl<T, false, false>
331 {
332     static T run(T x, T y)
333     {
334         const T max_value = integer_traits<T>::max();
335         if (x == 0 || y == 0) return true;
336         return x <= max_value / y;
337     }
338 };
339 
340 template<typename T> inline T is_mul_valid(T x, T y, T /*result not used*/)
341 {
342     return is_mul_valid_impl<T>::run(x, y);
343 }
344 
345 template<typename T> inline T is_div_valid(T x, T y)
346 {
347     return integer_traits<T>::is_signed ?
348                         // keep in mind that min/-1 is invalid because abs(min)>max
349                         y != 0 && (x != integer_traits<T>::min() || y != T(-1))
350                     :
351                         y != 0;
352 }
353 
354 } // end namespace CheckedInt_internal
355 
356 
357 /*** Step 4: Now define the CheckedInt class.
358  ***/
359 
360 /** \class CheckedInt
361   * \brief Integer wrapper class checking for integer overflow and other errors
362   * \param T the integer type to wrap. Can be any of int8_t, uint8_t, int16_t, uint16_t,
363   *          int32_t, uint32_t, int64_t, uint64_t.
364   *
365   * This class implements guarded integer arithmetic. Do a computation, then check that
366   * valid() returns true, you then have a guarantee that no problem, such as integer overflow,
367   * happened during this computation.
368   *
369   * The arithmetic operators in this class are guaranteed not to crash your app
370   * in case of a division by zero.
371   *
372   * For example, suppose that you want to implement a function that computes (x+y)/z,
373   * that doesn't crash if z==0, and that reports on error (divide by zero or integer overflow).
374   * You could code it as follows:
375     \code
376     bool compute_x_plus_y_over_z(int32_t x, int32_t y, int32_t z, int32_t *result)
377     {
378         CheckedInt<int32_t> checked_result = (CheckedInt<int32_t>(x) + y) / z;
379         *result = checked_result.value();
380         return checked_result.valid();
381     }
382     \endcode
383   *
384   * Implicit conversion from plain integers to checked integers is allowed. The plain integer
385   * is checked to be in range before being casted to the destination type. This means that the following
386   * lines all compile, and the resulting CheckedInts are correctly detected as valid or invalid:
387   * \code
388     CheckedInt<uint8_t> x(1);   // 1 is of type int, is found to be in range for uint8_t, x is valid
389     CheckedInt<uint8_t> x(-1);  // -1 is of type int, is found not to be in range for uint8_t, x is invalid
390     CheckedInt<int8_t> x(-1);   // -1 is of type int, is found to be in range for int8_t, x is valid
391     CheckedInt<int8_t> x(int16_t(1000)); // 1000 is of type int16_t, is found not to be in range for int8_t, x is invalid
392     CheckedInt<int32_t> x(uint32_t(123456789)); // 3123456789 is of type uint32_t, is found not to be in range
393                                              // for int32_t, x is invalid
394   * \endcode
395   * Implicit conversion from
396   * checked integers to plain integers is not allowed. As shown in the
397   * above example, to get the value of a checked integer as a normal integer, call value().
398   *
399   * Arithmetic operations between checked and plain integers is allowed; the result type
400   * is the type of the checked integer.
401   *
402   * Safe integers of different types cannot be used in the same arithmetic expression.
403   */
404 template<typename T>
405 class CheckedInt
406 {
407 protected:
408     T mValue;
409     T mIsValid; // stored as a T to limit the number of integer conversions when
410                 // evaluating nested arithmetic expressions.
411 
412     template<typename U>
413     CheckedInt(const U& value, bool isValid) : mValue(value), mIsValid(isValid)
414     {
415         CheckedInt_internal::TYPE_NOT_SUPPORTED_BY_CheckedInt<T>::run();
416     }
417 
418 public:
419     /** Constructs a checked integer with given \a value. The checked integer is initialized as valid or invalid
420       * depending on whether the \a value is in range.
421       *
422       * This constructor is not explicit. Instead, the type of its argument is a separate template parameter,
423       * ensuring that no conversion is performed before this constructor is actually called.
424       * As explained in the above documentation for class CheckedInt, this constructor checks that its argument is
425       * valid.
426       */
427     template<typename U>
428     CheckedInt(const U& value)
429         : mValue(value),
430           mIsValid(CheckedInt_internal::is_in_range<T>(value))
431     {
432         CheckedInt_internal::TYPE_NOT_SUPPORTED_BY_CheckedInt<T>::run();
433     }
434 
435     /** Constructs a valid checked integer with uninitialized value */
436     CheckedInt() : mIsValid(1)
437     {
438         CheckedInt_internal::TYPE_NOT_SUPPORTED_BY_CheckedInt<T>::run();
439     }
440 
441     /** \returns the actual value */
442     T value() const { return mValue; }
443 
444     /** \returns true if the checked integer is valid, i.e. is not the result
445       * of an invalid operation or of an operation involving an invalid checked integer
446       */
447     bool valid() const { return mIsValid; }
448 
449     /** \returns the sum. Checks for overflow. */
450     template<typename U> friend CheckedInt<U> operator +(const CheckedInt<U>& lhs, const CheckedInt<U>& rhs);
451     /** Adds. Checks for overflow. \returns self reference */
452     template<typename U> CheckedInt& operator +=(const U &rhs);
453     /** \returns the difference. Checks for overflow. */
454     template<typename U> friend CheckedInt<U> operator -(const CheckedInt<U>& lhs, const CheckedInt<U> &rhs);
455     /** Substracts. Checks for overflow. \returns self reference */
456     template<typename U> CheckedInt& operator -=(const U &rhs);
457     /** \returns the product. Checks for overflow. */
458     template<typename U> friend CheckedInt<U> operator *(const CheckedInt<U>& lhs, const CheckedInt<U> &rhs);
459     /** Multiplies. Checks for overflow. \returns self reference */
460     template<typename U> CheckedInt& operator *=(const U &rhs);
461     /** \returns the quotient. Checks for overflow and for divide-by-zero. */
462     template<typename U> friend CheckedInt<U> operator /(const CheckedInt<U>& lhs, const CheckedInt<U> &rhs);
463     /** Divides. Checks for overflow and for divide-by-zero. \returns self reference */
464     template<typename U> CheckedInt& operator /=(const U &rhs);
465 
466     /** \returns the opposite value. Checks for overflow. */
467     CheckedInt operator -() const
468     {
469         T result = -value();
470         /* give the compiler a good chance to perform RVO */
471         return CheckedInt(result,
472                        mIsValid & CheckedInt_internal::is_sub_valid(T(0), value(), result));
473     }
474 
475     /** \returns true if the left and right hand sides are valid and have the same value. */
476     bool operator ==(const CheckedInt& other) const
477     {
478         return bool(mIsValid & other.mIsValid & T(value() == other.value()));
479     }
480 
481 private:
482     /** operator!= is disabled. Indeed: (a!=b) should be the same as !(a==b) but that
483       * would mean that if a or b is invalid, (a!=b) is always true, which is very tricky.
484       */
485     template<typename U>
486     bool operator !=(const U& other) const { return !(*this == other); }
487 };
488 
489 #define CHECKEDINT_BASIC_BINARY_OPERATOR(NAME, OP)               \
490 template<typename T>                                          \
491 inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, const CheckedInt<T> &rhs) \
492 {                                                             \
493     T x = lhs.value();                                        \
494     T y = rhs.value();                                        \
495     T result = x OP y;                                        \
496     T is_op_valid                                             \
497         = CheckedInt_internal::is_##NAME##_valid(x, y, result);  \
498     /* give the compiler a good chance to perform RVO */      \
499     return CheckedInt<T>(result,                                 \
500                       lhs.mIsValid &                          \
501                       rhs.mIsValid &                          \
502                       is_op_valid);                           \
503 }
504 
505 CHECKEDINT_BASIC_BINARY_OPERATOR(add, +)
506 CHECKEDINT_BASIC_BINARY_OPERATOR(sub, -)
507 CHECKEDINT_BASIC_BINARY_OPERATOR(mul, *)
508 
509 // division can't be implemented by CHECKEDINT_BASIC_BINARY_OPERATOR
510 // because if rhs == 0, we are not allowed to even try to compute the quotient.
511 template<typename T>
512 inline CheckedInt<T> operator /(const CheckedInt<T> &lhs, const CheckedInt<T> &rhs)
513 {
514     T x = lhs.value();
515     T y = rhs.value();
516     T is_op_valid = CheckedInt_internal::is_div_valid(x, y);
517     T result = is_op_valid ? (x / y) : 0;
518     /* give the compiler a good chance to perform RVO */
519     return CheckedInt<T>(result,
520                       lhs.mIsValid &
521                       rhs.mIsValid &
522                       is_op_valid);
523 }
524 
525 // implement cast_to_CheckedInt<T>(x), making sure that
526 //  - it allows x to be either a CheckedInt<T> or any integer type that can be casted to T
527 //  - if x is already a CheckedInt<T>, we just return a reference to it, instead of copying it (optimization)
528 
529 template<typename T, typename U>
530 struct cast_to_CheckedInt_impl
531 {
532     typedef CheckedInt<T> return_type;
533     static CheckedInt<T> run(const U& u) { return u; }
534 };
535 
536 template<typename T>
537 struct cast_to_CheckedInt_impl<T, CheckedInt<T> >
538 {
539     typedef const CheckedInt<T>& return_type;
540     static const CheckedInt<T>& run(const CheckedInt<T>& u) { return u; }
541 };
542 
543 template<typename T, typename U>
544 inline typename cast_to_CheckedInt_impl<T, U>::return_type
545 cast_to_CheckedInt(const U& u)
546 {
547     return cast_to_CheckedInt_impl<T, U>::run(u);
548 }
549 
550 #define CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(OP, COMPOUND_OP) \
551 template<typename T>                                          \
552 template<typename U>                                          \
553 CheckedInt<T>& CheckedInt<T>::operator COMPOUND_OP(const U &rhs)    \
554 {                                                             \
555     *this = *this OP cast_to_CheckedInt<T>(rhs);                 \
556     return *this;                                             \
557 }                                                             \
558 template<typename T, typename U>                              \
559 inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, const U &rhs) \
560 {                                                             \
561     return lhs OP cast_to_CheckedInt<T>(rhs);                    \
562 }                                                             \
563 template<typename T, typename U>                              \
564 inline CheckedInt<T> operator OP(const U & lhs, const CheckedInt<T> &rhs) \
565 {                                                             \
566     return cast_to_CheckedInt<T>(lhs) OP rhs;                    \
567 }
568 
569 CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(+, +=)
570 CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(*, *=)
571 CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(-, -=)
572 CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(/, /=)
573 
574 template<typename T, typename U>
575 inline bool operator ==(const CheckedInt<T> &lhs, const U &rhs)
576 {
577     return lhs == cast_to_CheckedInt<T>(rhs);
578 }
579 
580 template<typename T, typename U>
581 inline bool operator ==(const U & lhs, const CheckedInt<T> &rhs)
582 {
583     return cast_to_CheckedInt<T>(lhs) == rhs;
584 }
585 
586 } // end namespace WebCore
587 
588 #endif /* CheckedInt_h */
589