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 | |
58 | template <typename Dst, typename Src> |
59 | inline 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). |
128 | template <INT64 DstMin, UINT64 DstMax> |
129 | inline 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 | |
136 | template <INT64 DstMin, UINT64 DstMax> |
137 | inline 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). |
188 | template<typename T> class ClrSafeInt |
189 | { |
190 | public: |
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 | |
795 | private: |
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. |
836 | template <typename T> |
837 | ClrSafeInt<T> AsClrSafeInt(T t) |
838 | { |
839 | return ClrSafeInt<T>(t); |
840 | } |
841 | |
842 | template <typename T> |
843 | ClrSafeInt<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 |
851 | typedef ClrSafeInt<UINT8> S_UINT8; |
852 | typedef ClrSafeInt<UINT16> S_UINT16; |
853 | //typedef ClrSafeInt<UINT32> S_UINT32; |
854 | #define S_UINT32 ClrSafeInt<UINT32> |
855 | typedef ClrSafeInt<UINT64> S_UINT64; |
856 | typedef ClrSafeInt<SIZE_T> S_SIZE_T; |
857 | |
858 | #endif // SAFEMATH_H_ |
859 | |