1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4// ---------------------------------------------------------------------------
5// safemath.h
6//
7// overflow checking infrastructure
8// ---------------------------------------------------------------------------
9
10
11#ifndef SAFEMATH_H_
12#define SAFEMATH_H_
13
14// This file is included from several places outside the CLR, so we can't
15// pull in files like DebugMacros.h. However, we assume that the standard
16// clrtypes (UINT32 etc.) are defined.
17#include "debugmacrosext.h"
18
19#ifndef _ASSERTE_SAFEMATH
20#ifdef _ASSERTE
21// Use _ASSERTE if we have it (should always be the case in the CLR)
22#define _ASSERTE_SAFEMATH _ASSERTE
23#else
24// Otherwise (eg. we're being used from a tool like SOS) there isn't much
25// we can rely on that is available everywhere. In
26// several other tools we just take the recourse of disabling asserts,
27// we'll do the same here.
28// Ideally we'd have a collection of common utilities available evererywhere.
29#define _ASSERTE_SAFEMATH(a)
30#endif
31#endif
32
33#include "static_assert.h"
34
35#ifdef PAL_STDCPP_COMPAT
36#include <type_traits>
37#else
38#include "clr_std/type_traits"
39#endif
40
41//==================================================================
42// Semantics: if val can be represented as the exact same value
43// when cast to Dst type, then FitsIn<Dst>(val) will return true;
44// otherwise FitsIn returns false.
45//
46// Dst and Src must both be integral types.
47//
48// It's important to note that most of the conditionals in this
49// function are based on static type information and as such will
50// be optimized away. In particular, the case where the signs are
51// identical will result in no code branches.
52
53#ifdef _PREFAST_
54#pragma warning(push)
55#pragma warning(disable:6326) // PREfast warning: Potential comparison of a constant with another constant
56#endif // _PREFAST_
57
58template <typename Dst, typename Src>
59inline bool FitsIn(Src val)
60{
61#ifdef _MSC_VER
62 static_assert_no_msg(!__is_class(Dst));
63 static_assert_no_msg(!__is_class(Src));
64#endif
65
66 if (std::is_signed<Src>::value == std::is_signed<Dst>::value)
67 { // Src and Dst are equally signed
68 if (sizeof(Src) <= sizeof(Dst))
69 { // No truncation is possible
70 return true;
71 }
72 else
73 { // Truncation is possible, requiring runtime check
74 return val == (Src)((Dst)val);
75 }
76 }
77 else if (std::is_signed<Src>::value)
78 { // Src is signed, Dst is unsigned
79#ifdef __GNUC__
80 // Workaround for GCC warning: "comparison is always
81 // false due to limited range of data type."
82 if (!(val == 0 || val > 0))
83#else
84 if (val < 0)
85#endif
86 { // A negative number cannot be represented by an unsigned type
87 return false;
88 }
89 else
90 {
91 if (sizeof(Src) <= sizeof(Dst))
92 { // No truncation is possible
93 return true;
94 }
95 else
96 { // Truncation is possible, requiring runtime check
97 return val == (Src)((Dst)val);
98 }
99 }
100 }
101 else
102 { // Src is unsigned, Dst is signed
103 if (sizeof(Src) < sizeof(Dst))
104 { // No truncation is possible. Note that Src is strictly
105 // smaller than Dst.
106 return true;
107 }
108 else
109 { // Truncation is possible, requiring runtime check
110#ifdef __GNUC__
111 // Workaround for GCC warning: "comparison is always
112 // true due to limited range of data type." If in fact
113 // Dst were unsigned we'd never execute this code
114 // anyway.
115 return ((Dst)val > 0 || (Dst)val == 0) &&
116#else
117 return ((Dst)val >= 0) &&
118#endif
119 (val == (Src)((Dst)val));
120 }
121 }
122}
123
124// Requires that Dst is an integral type, and that DstMin and DstMax are the
125// minimum and maximum values of that type, respectively. Returns "true" iff
126// "val" can be represented in the range [DstMin..DstMax] (allowing loss of precision, but
127// not truncation).
128template <INT64 DstMin, UINT64 DstMax>
129inline bool FloatFitsInIntType(float val)
130{
131 float DstMinF = static_cast<float>(DstMin);
132 float DstMaxF = static_cast<float>(DstMax);
133 return DstMinF <= val && val <= DstMaxF;
134}
135
136template <INT64 DstMin, UINT64 DstMax>
137inline bool DoubleFitsInIntType(double val)
138{
139 double DstMinD = static_cast<double>(DstMin);
140 double DstMaxD = static_cast<double>(DstMax);
141 return DstMinD <= val && val <= DstMaxD;
142}
143
144#ifdef _PREFAST_
145#pragma warning(pop)
146#endif //_PREFAST_
147
148#define ovadd_lt(a, b, rhs) (((a) + (b) < (rhs) ) && ((a) + (b) >= (a)))
149#define ovadd_le(a, b, rhs) (((a) + (b) <= (rhs) ) && ((a) + (b) >= (a)))
150#define ovadd_gt(a, b, rhs) (((a) + (b) > (rhs) ) || ((a) + (b) < (a)))
151#define ovadd_ge(a, b, rhs) (((a) + (b) >= (rhs) ) || ((a) + (b) < (a)))
152
153#define ovadd3_gt(a, b, c, rhs) (((a) + (b) + (c) > (rhs)) || ((a) + (b) < (a)) || ((a) + (b) + (c) < (c)))
154
155
156 //-----------------------------------------------------------------------------
157//
158// Liberally lifted from the Office example on MSDN and modified.
159// http://msdn.microsoft.com/library/en-us/dncode/html/secure01142004.asp
160//
161// Modified to track an overflow bit instead of throwing exceptions. In most
162// cases the Visual C++ optimizer (Whidbey beta1 - v14.00.40607) is able to
163// optimize the bool away completely.
164// Note that using a sentinal value (IntMax for example) to represent overflow
165// actually results in poorer code-gen.
166//
167// This has also been simplified significantly to remove functionality we
168// don't currently want (division, implicit conversions, many additional operators etc.)
169//
170// Example:
171// unsafe: UINT32 bufSize = headerSize + elementCount * sizeof(void*);
172// becomes:
173// S_UINT32 bufSize = S_UINT32(headerSize) + S_UINT32(elementCount) *
174// S_UINT32( sizeof(void*) );
175// if( bufSize.IsOverflow() ) { <overflow-error> }
176// else { use bufSize.Value() }
177// or:
178// UINT32 tmp, bufSize;
179// if( !ClrSafeInt<UINT32>::multiply( elementCount, sizeof(void*), tmp ) ||
180// !ClrSafeInt<UINT32>::addition( tmp, headerSize, bufSize ) )
181// { <overflow-error> }
182// else { use bufSize }
183//
184//-----------------------------------------------------------------------------
185// TODO: Any way to prevent unintended instantiations? This is only designed to
186// work with unsigned integral types (signed types will work but we probably
187// don't need signed support).
188template<typename T> class ClrSafeInt
189{
190public:
191 // Default constructor - 0 value by default
192 ClrSafeInt() :
193 m_value(0),
194 m_overflow(false)
195 COMMA_INDEBUG( m_checkedOverflow( false ) )
196 {
197 }
198
199 // Value constructor
200 // This is explicit because otherwise it would be harder to
201 // differentiate between checked and unchecked usage of an operator.
202 // I.e. si + x + y vs. si + ( x + y )
203 //
204 // Set the m_checkedOverflow bit to true since this is being initialized
205 // with a constant value and we know that it is valid. A scenario in
206 // which this is useful is when an overflow causes a fallback value to
207 // be used:
208 // if (val.IsOverflow())
209 // val = ClrSafeInt<T>(some_value);
210 explicit ClrSafeInt( T v ) :
211 m_value(v),
212 m_overflow(false)
213 COMMA_INDEBUG( m_checkedOverflow( true ) )
214 {
215 }
216
217 template <typename U>
218 explicit ClrSafeInt(U u) :
219 m_value(0),
220 m_overflow(false)
221 COMMA_INDEBUG( m_checkedOverflow( false ) )
222 {
223 if (!FitsIn<T>(u))
224 {
225 m_overflow = true;
226 }
227 else
228 {
229 m_value = (T)u;
230 }
231 }
232
233 template <typename U>
234 ClrSafeInt(ClrSafeInt<U> u) :
235 m_value(0),
236 m_overflow(false)
237 COMMA_INDEBUG( m_checkedOverflow( false ) )
238 {
239 if (u.IsOverflow() || !FitsIn<T>(u.Value()))
240 {
241 m_overflow = true;
242 }
243 else
244 {
245 m_value = (T)u.Value();
246 }
247 }
248
249 // Note: compiler-generated copy constructor and assignment operator
250 // are correct for our purposes.
251
252 // Note: The MS compiler will sometimes silently perform value-destroying
253 // conversions when calling the operators below.
254 // Eg. "ClrSafeInt<unsigned> s(0); s += int(-1);" will result in s
255 // having the value 0xffffffff without generating a compile-time warning.
256 // Narrowing conversions are generally level 4 warnings so may or may not
257 // be visible.
258 //
259 // In the original SafeInt class, all operators have an
260 // additional overload that takes an arbitrary type U and then safe
261 // conversions are performed (resulting in overflow whenever the value
262 // cannot be preserved).
263 // We could do the same thing, but currently don't because:
264 // - we don't believe there are common cases where this would result in a
265 // security hole.
266 // - the extra complexity isn't worth the benefits
267 // - it would prevent compiler warnings in the cases we do get warnings for.
268
269
270 // true if there has been an overflow leading up to the creation of this
271 // value, false otherwise.
272 // Note that in debug builds we track whether our client called this,
273 // so we should not be calling this method ourselves from within this class.
274 inline bool IsOverflow() const
275 {
276 INDEBUG( m_checkedOverflow = true; )
277 return m_overflow;
278 }
279
280 // Get the value of this integer.
281 // Must only be called when IsOverflow()==false. If this is called
282 // on overflow we'll assert in Debug and return 0 in release.
283 inline T Value() const
284 {
285 _ASSERTE_SAFEMATH( m_checkedOverflow ); // Ensure our caller first checked the overflow bit
286 _ASSERTE_SAFEMATH( !m_overflow );
287 return m_value;
288 }
289
290 // force the value into the overflow state.
291 inline void SetOverflow()
292 {
293 INDEBUG( this->m_checkedOverflow = false; )
294 this->m_overflow = true;
295 // incase someone manages to call Value in release mode - should be optimized out
296 this->m_value = 0;
297 }
298
299
300 //
301 // OPERATORS
302 //
303
304 // Addition and multiplication. Only permitted when both sides are explicitly
305 // wrapped inside of a ClrSafeInt and when the types match exactly.
306 // If we permitted a RHS of type 'T', then there would be differences
307 // in correctness between mathematically equivalent expressions such as
308 // "si + x + y" and "si + ( x + y )". Unfortunately, not permitting this
309 // makes expressions involving constants tedius and ugly since the constants
310 // must be wrapped in ClrSafeInt instances. If we become confident that
311 // our tools (PreFast) will catch all integer overflows, then we can probably
312 // safely add this.
313 inline ClrSafeInt<T> operator +(ClrSafeInt<T> rhs) const
314 {
315 ClrSafeInt<T> result; // value is initialized to 0
316 if( this->m_overflow ||
317 rhs.m_overflow ||
318 !addition( this->m_value, rhs.m_value, result.m_value ) )
319 {
320 result.m_overflow = true;
321 }
322
323 return result;
324 }
325
326 inline ClrSafeInt<T> operator -(ClrSafeInt<T> rhs) const
327 {
328 ClrSafeInt<T> result; // value is initialized to 0
329 if( this->m_overflow ||
330 rhs.m_overflow ||
331 !subtraction( this->m_value, rhs.m_value, result.m_value ) )
332 {
333 result.m_overflow = true;
334 }
335
336 return result;
337 }
338
339 inline ClrSafeInt<T> operator *(ClrSafeInt<T> rhs) const
340 {
341 ClrSafeInt<T> result; // value is initialized to 0
342 if( this->m_overflow ||
343 rhs.m_overflow ||
344 !multiply( this->m_value, rhs.m_value, result.m_value ) )
345 {
346 result.m_overflow = true;
347 }
348
349 return result;
350 }
351
352 // Accumulation operators
353 // Here it's ok to have versions that take a value of type 'T', however we still
354 // don't allow any mixed-type operations.
355 inline ClrSafeInt<T>& operator +=(ClrSafeInt<T> rhs)
356 {
357 INDEBUG( this->m_checkedOverflow = false; )
358 if( this->m_overflow ||
359 rhs.m_overflow ||
360 !ClrSafeInt<T>::addition( this->m_value, rhs.m_value, this->m_value ) )
361 {
362 this->SetOverflow();
363 }
364 return *this;
365 }
366
367 inline ClrSafeInt<T>& operator +=(T rhs)
368 {
369 INDEBUG( this->m_checkedOverflow = false; )
370 if( this->m_overflow ||
371 !ClrSafeInt<T>::addition( this->m_value, rhs, this->m_value ) )
372 {
373 this->SetOverflow();
374 }
375 return *this;
376 }
377
378 inline ClrSafeInt<T>& operator *=(ClrSafeInt<T> rhs)
379 {
380 INDEBUG( this->m_checkedOverflow = false; )
381 if( this->m_overflow ||
382 rhs.m_overflow ||
383 !ClrSafeInt<T>::multiply( this->m_value, rhs.m_value, this->m_value ) )
384 {
385 this->SetOverflow();
386 }
387 return *this;
388 }
389
390 inline ClrSafeInt<T>& operator *=(T rhs)
391 {
392 INDEBUG( this->m_checkedOverflow = false; )
393 if( this->m_overflow ||
394 !ClrSafeInt<T>::multiply( this->m_value, rhs, this->m_value ) )
395 {
396 this->SetOverflow();
397 }
398
399 return *this;
400 }
401
402 //
403 // STATIC HELPER METHODS
404 //these compile down to something as efficient as macros and allow run-time testing
405 //of type by the developer
406 //
407
408 template <typename U> static bool IsSigned(U)
409 {
410 return std::is_signed<U>::value;
411 }
412
413 static bool IsSigned()
414 {
415 return std::is_signed<T>::value;
416 }
417
418 static bool IsMixedSign(T lhs, T rhs)
419 {
420 return ((lhs ^ rhs) < 0);
421 }
422
423 static unsigned char BitCount(){return (sizeof(T)*8);}
424
425 static bool Is64Bit(){return sizeof(T) == 8;}
426 static bool Is32Bit(){return sizeof(T) == 4;}
427 static bool Is16Bit(){return sizeof(T) == 2;}
428 static bool Is8Bit(){return sizeof(T) == 1;}
429
430 //both of the following should optimize away
431 static T MaxInt()
432 {
433 if(IsSigned())
434 {
435 return (T)~((T)1 << (BitCount()-1));
436 }
437 //else
438 return (T)(~(T)0);
439 }
440
441 static T MinInt()
442 {
443 if(IsSigned())
444 {
445 return (T)((T)1 << (BitCount()-1));
446 }
447 else
448 {
449 return ((T)0);
450 }
451 }
452
453 // Align a value up to the nearest boundary, which must be a power of 2
454 inline void AlignUp( T alignment )
455 {
456 _ASSERTE_SAFEMATH( IsPowerOf2( alignment ) );
457 *this += (alignment - 1);
458 if( !this->m_overflow )
459 {
460 m_value &= ~(alignment - 1);
461 }
462 }
463
464 //
465 // Arithmetic implementation functions
466 //
467
468 //note - this looks complex, but most of the conditionals
469 //are constant and optimize away
470 //for example, a signed 64-bit check collapses to:
471/*
472 if(lhs == 0 || rhs == 0)
473 return 0;
474
475 if(MaxInt()/+lhs < +rhs)
476 {
477 //overflow
478 throw SafeIntException(ERROR_ARITHMETIC_OVERFLOW);
479 }
480 //ok
481 return lhs * rhs;
482
483 Which ought to inline nicely
484*/
485 // Returns true if safe, false for overflow.
486 static bool multiply(T lhs, T rhs, T &result)
487 {
488 if(Is64Bit())
489 {
490 //fast track this one - and avoid DIV_0 below
491 if(lhs == 0 || rhs == 0)
492 {
493 result = 0;
494 return true;
495 }
496
497 //we're 64 bit - slow, but the only way to do it
498 if(IsSigned())
499 {
500 if(!IsMixedSign(lhs, rhs))
501 {
502 //both positive or both negative
503 //result will be positive, check for lhs * rhs > MaxInt
504 if(lhs > 0)
505 {
506 //both positive
507 if(MaxInt()/lhs < rhs)
508 {
509 //overflow
510 return false;
511 }
512 }
513 else
514 {
515 //both negative
516
517 //comparison gets tricky unless we force it to positive
518 //EXCEPT that -MinInt is undefined - can't be done
519 //And MinInt always has a greater magnitude than MaxInt
520 if(lhs == MinInt() || rhs == MinInt())
521 {
522 //overflow
523 return false;
524 }
525
526#ifdef _MSC_VER
527#pragma warning( disable : 4146 ) // unary minus applied to unsigned is still unsigned
528#endif
529 if(MaxInt()/(-lhs) < (-rhs) )
530 {
531 //overflow
532 return false;
533 }
534#ifdef _MSC_VER
535#pragma warning( default : 4146 )
536#endif
537 }
538 }
539 else
540 {
541 //mixed sign - this case is difficult
542 //test case is lhs * rhs < MinInt => overflow
543 //if lhs < 0 (implies rhs > 0),
544 //lhs < MinInt/rhs is the correct test
545 //else if lhs > 0
546 //rhs < MinInt/lhs is the correct test
547 //avoid dividing MinInt by a negative number,
548 //because MinInt/-1 is a corner case
549
550 if(lhs < 0)
551 {
552 if(lhs < MinInt()/rhs)
553 {
554 //overflow
555 return false;
556 }
557 }
558 else
559 {
560 if(rhs < MinInt()/lhs)
561 {
562 //overflow
563 return false;
564 }
565 }
566 }
567
568 //ok
569 result = lhs * rhs;
570 return true;
571 }
572 else
573 {
574 //unsigned, easy case
575 if(MaxInt()/lhs < rhs)
576 {
577 //overflow
578 return false;
579 }
580 //ok
581 result = lhs * rhs;
582 return true;
583 }
584 }
585 else if(Is32Bit())
586 {
587 //we're 32-bit
588 if(IsSigned())
589 {
590 INT64 tmp = (INT64)lhs * (INT64)rhs;
591
592 //upper 33 bits must be the same
593 //most common case is likely that both are positive - test first
594 if( (tmp & 0xffffffff80000000LL) == 0 ||
595 (tmp & 0xffffffff80000000LL) == 0xffffffff80000000LL)
596 {
597 //this is OK
598 result = (T)tmp;
599 return true;
600 }
601
602 //overflow
603 return false;
604
605 }
606 else
607 {
608 UINT64 tmp = (UINT64)lhs * (UINT64)rhs;
609 if (tmp & 0xffffffff00000000ULL) //overflow
610 {
611 //overflow
612 return false;
613 }
614 result = (T)tmp;
615 return true;
616 }
617 }
618 else if(Is16Bit())
619 {
620 //16-bit
621 if(IsSigned())
622 {
623 INT32 tmp = (INT32)lhs * (INT32)rhs;
624 //upper 17 bits must be the same
625 //most common case is likely that both are positive - test first
626 if( (tmp & 0xffff8000) == 0 || (tmp & 0xffff8000) == 0xffff8000)
627 {
628 //this is OK
629 result = (T)tmp;
630 return true;
631 }
632
633 //overflow
634 return false;
635 }
636 else
637 {
638 UINT32 tmp = (UINT32)lhs * (UINT32)rhs;
639 if (tmp & 0xffff0000) //overflow
640 {
641 return false;
642 }
643 result = (T)tmp;
644 return true;
645 }
646 }
647 else //8-bit
648 {
649 _ASSERTE_SAFEMATH(Is8Bit());
650
651 if(IsSigned())
652 {
653 INT16 tmp = (INT16)lhs * (INT16)rhs;
654 //upper 9 bits must be the same
655 //most common case is likely that both are positive - test first
656 if( (tmp & 0xff80) == 0 || (tmp & 0xff80) == 0xff80)
657 {
658 //this is OK
659 result = (T)tmp;
660 return true;
661 }
662
663 //overflow
664 return false;
665 }
666 else
667 {
668 UINT16 tmp = ((UINT16)lhs) * ((UINT16)rhs);
669
670 if (tmp & 0xff00) //overflow
671 {
672 return false;
673 }
674 result = (T)tmp;
675 return true;
676 }
677 }
678 }
679
680 // Returns true if safe, false on overflow
681 static inline bool addition(T lhs, T rhs, T &result)
682 {
683 if(IsSigned())
684 {
685 //test for +/- combo
686 if(!IsMixedSign(lhs, rhs))
687 {
688 //either two negatives, or 2 positives
689#ifdef __GNUC__
690 // Workaround for GCC warning: "comparison is always
691 // false due to limited range of data type."
692 if (!(rhs == 0 || rhs > 0))
693#else
694 if(rhs < 0)
695#endif // __GNUC__ else
696 {
697 //two negatives
698 if(lhs < (T)(MinInt() - rhs)) //remember rhs < 0
699 {
700 return false;
701 }
702 //ok
703 }
704 else
705 {
706 //two positives
707 if((T)(MaxInt() - lhs) < rhs)
708 {
709 return false;
710 }
711 //OK
712 }
713 }
714 //else overflow not possible
715 result = lhs + rhs;
716 return true;
717 }
718 else //unsigned
719 {
720 if((T)(MaxInt() - lhs) < rhs)
721 {
722 return false;
723
724 }
725 result = lhs + rhs;
726 return true;
727 }
728 }
729
730 // Returns true if safe, false on overflow
731 static inline bool subtraction(T lhs, T rhs, T& result)
732 {
733 T tmp = lhs - rhs;
734
735 if(IsSigned())
736 {
737 if(IsMixedSign(lhs, rhs)) //test for +/- combo
738 {
739 //mixed positive and negative
740 //two cases - +X - -Y => X + Y - check for overflow against MaxInt()
741 // -X - +Y - check for overflow against MinInt()
742
743 if(lhs >= 0) //first case
744 {
745 //test is X - -Y > MaxInt()
746 //equivalent to X > MaxInt() - |Y|
747 //Y == MinInt() creates special case
748 //Even 0 - MinInt() can't be done
749 //note that the special case collapses into the general case, due to the fact
750 //MaxInt() - MinInt() == -1, and lhs is non-negative
751 //OR tmp should be GTE lhs
752
753 // old test - leave in for clarity
754 //if(lhs > (T)(MaxInt() + rhs)) //remember that rhs is negative
755 if(tmp < lhs)
756 {
757 return false;
758 }
759 //fall through to return value
760 }
761 else
762 {
763 //second case
764 //test is -X - Y < MinInt()
765 //or -X < MinInt() + Y
766 //we do not have the same issues because abs(MinInt()) > MaxInt()
767 //tmp should be LTE lhs
768
769 //if(lhs < (T)(MinInt() + rhs)) // old test - leave in for clarity
770 if(tmp > lhs)
771 {
772 return false;
773 }
774 //fall through to return value
775 }
776 }
777 // else
778 //both negative, or both positive
779 //no possible overflow
780 result = tmp;
781 return true;
782 }
783 else
784 {
785 //easy unsigned case
786 if(lhs < rhs)
787 {
788 return false;
789 }
790 result = tmp;
791 return true;
792 }
793 }
794
795private:
796 // Private helper functions
797 // Note that's it occasionally handy to call the arithmetic implementation
798 // functions above so we leave them public, even though we almost always use
799 // the operators instead.
800
801 // True if the specified value is a power of two.
802 static inline bool IsPowerOf2( T x )
803 {
804 // find the smallest power of 2 >= x
805 T testPow = 1;
806 while( testPow < x )
807 {
808 testPow = testPow << 1; // advance to next power of 2
809 if( testPow <= 0 )
810 {
811 return false; // overflow
812 }
813 }
814
815 return( testPow == x );
816 }
817
818 //
819 // Instance data
820 //
821
822 // The integer value this instance represents, or 0 if overflow.
823 T m_value;
824
825 // True if overflow has been reached. Once this is set, it cannot be cleared.
826 bool m_overflow;
827
828 // In debug builds we verify that our caller checked the overflow bit before
829 // accessing the value. This flag is cleared on initialization, and whenever
830 // m_value or m_overflow changes, and set only when IsOverflow
831 // is called.
832 INDEBUG( mutable bool m_checkedOverflow; )
833};
834
835// Allows creation of a ClrSafeInt corresponding to the type of the argument.
836template <typename T>
837ClrSafeInt<T> AsClrSafeInt(T t)
838{
839 return ClrSafeInt<T>(t);
840}
841
842template <typename T>
843ClrSafeInt<T> AsClrSafeInt(ClrSafeInt<T> t)
844{
845 return t;
846}
847
848// Convenience safe-integer types. Currently these are the only types
849// we are using ClrSafeInt with. We may want to add others.
850// These type names are based on our standardized names in clrtypes.h
851typedef ClrSafeInt<UINT8> S_UINT8;
852typedef ClrSafeInt<UINT16> S_UINT16;
853//typedef ClrSafeInt<UINT32> S_UINT32;
854#define S_UINT32 ClrSafeInt<UINT32>
855typedef ClrSafeInt<UINT64> S_UINT64;
856typedef ClrSafeInt<SIZE_T> S_SIZE_T;
857
858 #endif // SAFEMATH_H_
859