1 /*** 2 *safeint_internal.h - Internal details for SafeInt (see safeint.h) 3 * 4 * Copyright (c) Microsoft Corporation. All rights reserved. 5 * 6 *Purpose: 7 * Private internal details for SafeInt. 8 * The constructs and functions in Microsoft::Utilities::details are not 9 * meant to be used by external code and can change at any time. 10 * 11 ****/ 12 13 #pragma once 14 15 #include <crtdbg.h> 16 17 #pragma pack(push, _CRT_PACKING) 18 19 namespace msl 20 { 21 22 namespace utilities 23 { 24 25 namespace details 26 { 27 #pragma warning(push) 28 #pragma warning(disable:4702) 29 30 template < typename T > 31 class DependentFalse { public: enum{ value = false }; }; 32 33 template < typename T > class NumericType; 34 35 template <> class NumericType<bool> { public: enum{ isBool = true, isFloat = false, isInt = false }; }; 36 template <> class NumericType<char> { public: enum{ isBool = false, isFloat = false, isInt = true }; }; 37 template <> class NumericType<unsigned char> { public: enum{ isBool = false, isFloat = false, isInt = true }; }; 38 template <> class NumericType<signed char> { public: enum{ isBool = false, isFloat = false, isInt = true }; }; 39 template <> class NumericType<short> { public: enum{ isBool = false, isFloat = false, isInt = true }; }; 40 template <> class NumericType<unsigned short> { public: enum{ isBool = false, isFloat = false, isInt = true }; }; 41 #ifdef _NATIVE_WCHAR_T_DEFINED 42 template <> class NumericType<wchar_t> { public: enum{ isBool = false, isFloat = false, isInt = true }; }; 43 #endif /* _NATIVE_WCHAR_T_DEFINED */ 44 template <> class NumericType<int> { public: enum{ isBool = false, isFloat = false, isInt = true }; }; 45 template <> class NumericType<unsigned int> { public: enum{ isBool = false, isFloat = false, isInt = true }; }; 46 template <> class NumericType<long> { public: enum{ isBool = false, isFloat = false, isInt = true }; }; 47 template <> class NumericType<unsigned long> { public: enum{ isBool = false, isFloat = false, isInt = true }; }; 48 template <> class NumericType<__int64> { public: enum{ isBool = false, isFloat = false, isInt = true }; }; 49 template <> class NumericType<unsigned __int64> { public: enum{ isBool = false, isFloat = false, isInt = true }; }; 50 template <> class NumericType<float> { public: enum{ isBool = false, isFloat = true, isInt = false }; }; 51 template <> class NumericType<double> { public: enum{ isBool = false, isFloat = true, isInt = false }; }; 52 template <> class NumericType<long double> { public: enum{ isBool = false, isFloat = true, isInt = false }; }; 53 // Catch-all for anything not supported 54 template < typename T > class NumericType { public: enum{ isBool = false, isFloat = false, isInt = false }; }; 55 56 57 template < typename T > class IntTraits 58 { 59 public: 60 static_assert( NumericType<T>::isInt || NumericType<T>::isBool, "non-integral type T" ); 61 enum 62 { 63 #pragma warning(suppress:4804) 64 isSigned = ( (T)(-1) < 0 ), 65 is64Bit = ( sizeof(T) == 8 ), 66 is32Bit = ( sizeof(T) == 4 ), 67 is16Bit = ( sizeof(T) == 2 ), 68 is8Bit = ( sizeof(T) == 1 ), 69 isLT32Bit = ( sizeof(T) < 4 ), 70 isLT64Bit = ( sizeof(T) < 8 ), 71 isInt8 = ( sizeof(T) == 1 && isSigned ), 72 isUint8 = ( sizeof(T) == 1 && !isSigned ), 73 isInt16 = ( sizeof(T) == 2 && isSigned ), 74 isUint16 = ( sizeof(T) == 2 && !isSigned ), 75 isInt32 = ( sizeof(T) == 4 && isSigned ), 76 isUint32 = ( sizeof(T) == 4 && !isSigned ), 77 isInt64 = ( sizeof(T) == 8 && isSigned ), 78 isUint64 = ( sizeof(T) == 8 && !isSigned ), 79 bitCount = ( sizeof(T)*8 ), 80 #pragma warning(suppress:4804) 81 isBool = NumericType<T>::isBool 82 }; 83 84 #pragma warning(push) 85 #pragma warning(disable:4310) 86 #pragma warning(disable:4804) // suppress warning about '<<' being an unsafe operation when T is bool 87 const static T maxInt = isSigned ? ((T)~((T)1 << (T)(bitCount-1))) : ((T)(~(T)0)); 88 const static T minInt = isSigned ? ((T)((T)1 << (T)(bitCount-1))) : ((T)0); 89 #pragma warning(pop) 90 }; 91 92 // this is strictly internal and not to be used as a policy in SafeInt<> 93 struct SafeIntErrorPolicy_NoThrow 94 { SafeIntOnOverflowSafeIntErrorPolicy_NoThrow95 static void SafeIntOnOverflow() 96 { 97 } 98 SafeIntOnDivZeroSafeIntErrorPolicy_NoThrow99 static void SafeIntOnDivZero() 100 { 101 } 102 }; 103 104 template < typename T, typename U > class SafeIntCompare 105 { 106 public: 107 enum 108 { 109 isBothSigned = (IntTraits< T >::isSigned && IntTraits< U >::isSigned), 110 isBothUnsigned = (!IntTraits< T >::isSigned && !IntTraits< U >::isSigned), 111 isLikeSigned = (static_cast<bool>(IntTraits< T >::isSigned) == static_cast<bool>(IntTraits< U >::isSigned)), 112 isCastOK = ((isLikeSigned && sizeof(T) >= sizeof(U)) || 113 (IntTraits< T >::isSigned && sizeof(T) > sizeof(U))), 114 isBothLT32Bit = (IntTraits< T >::isLT32Bit && IntTraits< U >::isLT32Bit), 115 isBothLT64Bit = (IntTraits< T >::isLT64Bit && IntTraits< U >::isLT64Bit) 116 }; 117 }; 118 119 template < typename U > class SafeIntCompare< float, U > 120 { 121 public: 122 enum 123 { 124 isBothSigned = IntTraits< U >::isSigned, 125 isBothUnsigned = false, 126 isLikeSigned = IntTraits< U >::isSigned, 127 isCastOK = true 128 }; 129 }; 130 131 template < typename U > class SafeIntCompare< double, U > 132 { 133 public: 134 enum 135 { 136 isBothSigned = IntTraits< U >::isSigned, 137 isBothUnsigned = false, 138 isLikeSigned = IntTraits< U >::isSigned, 139 isCastOK = true 140 }; 141 }; 142 143 template < typename U > class SafeIntCompare< long double, U > 144 { 145 public: 146 enum 147 { 148 isBothSigned = IntTraits< U >::isSigned, 149 isBothUnsigned = false, 150 isLikeSigned = IntTraits< U >::isSigned, 151 isCastOK = true 152 }; 153 }; 154 155 //all of the arithmetic operators can be solved by the same code within 156 //each of these regions without resorting to compile-time constant conditionals 157 //most operators collapse the problem into less than the 22 zones, but this is used 158 //as the first cut 159 //using this also helps ensure that we handle all of the possible cases correctly 160 161 template < typename T, typename U > class IntRegion 162 { 163 public: 164 enum 165 { 166 //unsigned-unsigned zone 167 IntZone_UintLT32_UintLT32 = SafeIntCompare< T,U >::isBothUnsigned && SafeIntCompare< T,U >::isBothLT32Bit, 168 IntZone_Uint32_UintLT64 = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::is32Bit && IntTraits< U >::isLT64Bit, 169 IntZone_UintLT32_Uint32 = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::isLT32Bit && IntTraits< U >::is32Bit, 170 IntZone_Uint64_Uint = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::is64Bit, 171 IntZone_UintLT64_Uint64 = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::isLT64Bit && IntTraits< U >::is64Bit, 172 //unsigned-signed 173 IntZone_UintLT32_IntLT32 = !IntTraits< T >::isSigned && IntTraits< U >::isSigned && SafeIntCompare< T,U >::isBothLT32Bit, 174 IntZone_Uint32_IntLT64 = IntTraits< T >::isUint32 && IntTraits< U >::isSigned && IntTraits< U >::isLT64Bit, 175 IntZone_UintLT32_Int32 = !IntTraits< T >::isSigned && IntTraits< T >::isLT32Bit && IntTraits< U >::isInt32, 176 IntZone_Uint64_Int = IntTraits< T >::isUint64 && IntTraits< U >::isSigned && IntTraits< U >::isLT64Bit, 177 IntZone_UintLT64_Int64 = !IntTraits< T >::isSigned && IntTraits< T >::isLT64Bit && IntTraits< U >::isInt64, 178 IntZone_Uint64_Int64 = IntTraits< T >::isUint64 && IntTraits< U >::isInt64, 179 //signed-signed 180 IntZone_IntLT32_IntLT32 = SafeIntCompare< T,U >::isBothSigned && SafeIntCompare< T, U >::isBothLT32Bit, 181 IntZone_Int32_IntLT64 = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::is32Bit && IntTraits< U >::isLT64Bit, 182 IntZone_IntLT32_Int32 = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::isLT32Bit && IntTraits< U >::is32Bit, 183 IntZone_Int64_Int64 = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::isInt64 && IntTraits< U >::isInt64, 184 IntZone_Int64_Int = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::is64Bit && IntTraits< U >::isLT64Bit, 185 IntZone_IntLT64_Int64 = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::isLT64Bit && IntTraits< U >::is64Bit, 186 //signed-unsigned 187 IntZone_IntLT32_UintLT32 = IntTraits< T >::isSigned && !IntTraits< U >::isSigned && SafeIntCompare< T,U >::isBothLT32Bit, 188 IntZone_Int32_UintLT32 = IntTraits< T >::isInt32 && !IntTraits< U >::isSigned && IntTraits< U >::isLT32Bit, 189 IntZone_IntLT64_Uint32 = IntTraits< T >::isSigned && IntTraits< T >::isLT64Bit && IntTraits< U >::isUint32, 190 IntZone_Int64_UintLT64 = IntTraits< T >::isInt64 && !IntTraits< U >::isSigned && IntTraits< U >::isLT64Bit, 191 IntZone_Int_Uint64 = IntTraits< T >::isSigned && IntTraits< U >::isUint64 && IntTraits< T >::isLT64Bit, 192 IntZone_Int64_Uint64 = IntTraits< T >::isInt64 && IntTraits< U >::isUint64 193 }; 194 }; 195 196 // useful function to help with getting the magnitude of a negative number 197 enum AbsMethod 198 { 199 AbsMethodInt, 200 AbsMethodInt64, 201 AbsMethodNoop 202 }; 203 204 template < typename T > 205 class GetAbsMethod 206 { 207 public: 208 enum 209 { 210 method = IntTraits< T >::isLT64Bit && IntTraits< T >::isSigned ? AbsMethodInt : 211 IntTraits< T >::isInt64 ? AbsMethodInt64 : AbsMethodNoop 212 }; 213 }; 214 215 template < typename T, int Method = GetAbsMethod< T >::method > class AbsValueHelper; 216 217 template < typename T > class AbsValueHelper < T, AbsMethodInt > 218 { 219 public: Abs(T t)220 static unsigned __int32 Abs( T t ) throw() 221 { 222 _ASSERTE( t < 0 ); 223 return (unsigned __int32)-t; 224 } 225 }; 226 227 template < typename T > class AbsValueHelper < T, AbsMethodInt64 > 228 { 229 public: Abs(T t)230 static unsigned __int64 Abs( T t ) throw() 231 { 232 _ASSERTE( t < 0 ); 233 return (unsigned __int64)-t; 234 } 235 }; 236 237 template < typename T > class AbsValueHelper < T, AbsMethodNoop > 238 { 239 public: Abs(T t)240 static T Abs( T t ) throw() 241 { 242 // Why are you calling Abs on an unsigned number ??? 243 _ASSERTE( ("AbsValueHelper::Abs should not be called with an unsigned integer type", 0) ); 244 return t; 245 } 246 }; 247 248 template < typename T, typename E, bool fSigned > class NegationHelper; 249 250 template < typename T, typename E > class NegationHelper < T, E, true > // Signed 251 { 252 public: Negative(T t,T & ret)253 static SafeIntError Negative( T t, T& ret ) 254 { 255 // corner case 256 if( t != IntTraits< T >::minInt ) 257 { 258 // cast prevents unneeded checks in the case of small ints 259 ret = -t; 260 return SafeIntNoError; 261 } 262 E::SafeIntOnOverflow(); 263 return SafeIntArithmeticOverflow; 264 } 265 }; 266 267 268 template < typename T, typename E > class NegationHelper < T, E, false > // unsigned 269 { 270 public: Negative(T t,T & ret)271 static SafeIntError Negative( T t, T& ret ) throw() 272 { 273 _SAFEINT_UNSIGNED_NEGATION_BEHAVIOR(); 274 275 #pragma warning(suppress:4127) 276 _ASSERTE( !IntTraits<T>::isLT32Bit ); 277 278 #pragma warning(suppress:4146) 279 ret = -t; 280 return SafeIntNoError; 281 } 282 }; 283 284 //core logic to determine casting behavior 285 enum CastMethod 286 { 287 CastOK = 0, 288 CastCheckLTZero, 289 CastCheckGTMax, 290 CastCheckMinMaxUnsigned, 291 CastCheckMinMaxSigned, 292 CastFromFloat, 293 CastToBool, 294 CastFromBool 295 }; 296 297 template < typename ToType, typename FromType > 298 class GetCastMethod 299 { 300 public: 301 enum 302 { 303 method = ( IntTraits< FromType >::isBool && 304 !IntTraits< ToType >::isBool ) ? CastFromBool : 305 306 ( !IntTraits< FromType >::isBool && 307 IntTraits< ToType >::isBool ) ? CastToBool : 308 ( NumericType< FromType >::isFloat && 309 !NumericType< ToType >::isFloat ) ? CastFromFloat : 310 311 ( SafeIntCompare< ToType, FromType >::isCastOK || 312 ( NumericType< ToType >::isFloat && 313 !NumericType< FromType >::isFloat ) ) ? CastOK : 314 315 ( ( IntTraits< ToType >::isSigned && 316 !IntTraits< FromType >::isSigned && 317 sizeof( FromType ) >= sizeof( ToType ) ) || 318 ( SafeIntCompare< ToType, FromType >::isBothUnsigned && 319 sizeof( FromType ) > sizeof( ToType ) ) ) ? CastCheckGTMax : 320 321 ( !IntTraits< ToType >::isSigned && 322 IntTraits< FromType >::isSigned && 323 sizeof( ToType ) >= sizeof( FromType ) ) ? CastCheckLTZero : 324 325 ( !IntTraits< ToType >::isSigned ) ? CastCheckMinMaxUnsigned 326 : CastCheckMinMaxSigned 327 }; 328 }; 329 330 template < typename T, typename U, typename E, 331 int Method = GetCastMethod< T, U >::method > class SafeCastHelper; 332 333 template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastOK > 334 { 335 public: Cast(U u,T & t)336 static SafeIntError Cast( U u, T& t ) throw() 337 { 338 t = (T)u; 339 return SafeIntNoError; 340 } 341 }; 342 343 // special case floats and doubles 344 // tolerate loss of precision 345 template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastFromFloat > 346 { 347 public: Cast(U u,T & t)348 static SafeIntError Cast( U u, T& t ) 349 { 350 if( u <= (U)IntTraits< T >::maxInt && 351 u >= (U)IntTraits< T >::minInt ) 352 { 353 t = (T)u; 354 return SafeIntNoError; 355 } 356 357 E::SafeIntOnOverflow(); 358 return SafeIntArithmeticOverflow; 359 } 360 }; 361 362 // Match on any method where a bool is cast to type T 363 template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastFromBool > 364 { 365 public: Cast(bool b,T & t)366 static SafeIntError Cast( bool b, T& t ) throw() 367 { 368 t = (T)( b ? 1 : 0 ); 369 return SafeIntNoError; 370 } 371 }; 372 373 template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastToBool > 374 { 375 public: Cast(T t,bool & b)376 static SafeIntError Cast( T t, bool& b ) throw() 377 { 378 b = !!t; 379 return SafeIntNoError; 380 } 381 }; 382 383 template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastCheckLTZero > 384 { 385 public: Cast(U u,T & t)386 static SafeIntError Cast( U u, T& t ) 387 { 388 if( u < 0 ) 389 { 390 E::SafeIntOnOverflow(); 391 return SafeIntArithmeticOverflow; 392 } 393 394 t = (T)u; 395 return SafeIntNoError; 396 } 397 }; 398 399 template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastCheckGTMax > 400 { 401 public: Cast(U u,T & t)402 static SafeIntError Cast( U u, T& t ) 403 { 404 if( u > IntTraits< T >::maxInt ) 405 { 406 E::SafeIntOnOverflow(); 407 return SafeIntArithmeticOverflow; 408 } 409 410 t = (T)u; 411 return SafeIntNoError; 412 } 413 }; 414 415 template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastCheckMinMaxUnsigned > 416 { 417 public: Cast(U u,T & t)418 static SafeIntError Cast( U u, T& t ) 419 { 420 // U is signed - T could be either signed or unsigned 421 if( u > IntTraits< T >::maxInt || u < 0 ) 422 { 423 E::SafeIntOnOverflow(); 424 return SafeIntArithmeticOverflow; 425 } 426 427 t = (T)u; 428 return SafeIntNoError; 429 } 430 }; 431 432 template < typename T, typename U, typename E > class SafeCastHelper < T, U, E, CastCheckMinMaxSigned > 433 { 434 public: Cast(U u,T & t)435 static SafeIntError Cast( U u, T& t ) 436 { 437 // T, U are signed 438 if( u > IntTraits< T >::maxInt || u < IntTraits< T >::minInt ) 439 { 440 E::SafeIntOnOverflow(); 441 return SafeIntArithmeticOverflow; 442 } 443 444 t = (T)u; 445 return SafeIntNoError; 446 } 447 }; 448 449 //core logic to determine whether a comparison is valid, or needs special treatment 450 enum ComparisonMethod 451 { 452 ComparisonMethod_Ok = 0, 453 ComparisonMethod_CastInt, 454 ComparisonMethod_CastInt64, 455 ComparisonMethod_UnsignedT, 456 ComparisonMethod_UnsignedU 457 }; 458 459 template < typename T, typename U > 460 class ValidComparison 461 { 462 public: 463 enum 464 { 465 #if _SAFEINT_USE_ANSI_CONVERSIONS 466 method = ComparisonMethod_Ok 467 #else /* _SAFEINT_USE_ANSI_CONVERSIONS */ 468 method = ( ( SafeIntCompare< T, U >::isLikeSigned ) ? ComparisonMethod_Ok : 469 ( ( IntTraits< T >::isSigned && sizeof(T) < 8 && sizeof(U) < 4 ) || 470 ( IntTraits< U >::isSigned && sizeof(T) < 4 && sizeof(U) < 8 ) ) ? ComparisonMethod_CastInt : 471 ( ( IntTraits< T >::isSigned && sizeof(U) < 8 ) || 472 ( IntTraits< U >::isSigned && sizeof(T) < 8 ) ) ? ComparisonMethod_CastInt64 : 473 ( !IntTraits< T >::isSigned ) ? ComparisonMethod_UnsignedT : 474 ComparisonMethod_UnsignedU ) 475 #endif /* _SAFEINT_USE_ANSI_CONVERSIONS */ 476 }; 477 }; 478 479 template <typename T, typename U, int Method = ValidComparison< T, U >::method > class EqualityTest; 480 481 template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_Ok > 482 { 483 public: IsEquals(const T t,const U u)484 static bool IsEquals( const T t, const U u ) throw() { return ( t == u ); } 485 }; 486 487 template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_CastInt > 488 { 489 public: IsEquals(const T t,const U u)490 static bool IsEquals( const T t, const U u ) throw() { return ( (int)t == (int)u ); } 491 }; 492 493 template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_CastInt64 > 494 { 495 public: IsEquals(const T t,const U u)496 static bool IsEquals( const T t, const U u ) throw() { return ( (__int64)t == (__int64)u ); } 497 }; 498 499 template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_UnsignedT > 500 { 501 public: IsEquals(const T t,const U u)502 static bool IsEquals( const T t, const U u ) throw() 503 { 504 //one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller 505 if( u < 0 ) 506 { 507 return false; 508 } 509 510 //else safe to cast to type T 511 return ( t == (T)u ); 512 } 513 }; 514 515 template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_UnsignedU> 516 { 517 public: IsEquals(const T t,const U u)518 static bool IsEquals( const T t, const U u ) throw() 519 { 520 //one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller 521 if( t < 0 ) 522 { 523 return false; 524 } 525 526 //else safe to cast to type U 527 return ( (U)t == u ); 528 } 529 }; 530 531 template <typename T, typename U, int Method = ValidComparison< T, U >::method > class GreaterThanTest; 532 533 template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_Ok > 534 { 535 public: GreaterThan(const T t,const U u)536 static bool GreaterThan( const T t, const U u ) throw() { return ( t > u ); } 537 }; 538 539 template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_CastInt > 540 { 541 public: GreaterThan(const T t,const U u)542 static bool GreaterThan( const T t, const U u ) throw() { return ( (int)t > (int)u ); } 543 }; 544 545 template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_CastInt64 > 546 { 547 public: GreaterThan(const T t,const U u)548 static bool GreaterThan( const T t, const U u ) throw() { return ( (__int64)t > (__int64)u ); } 549 }; 550 551 template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_UnsignedT > 552 { 553 public: GreaterThan(const T t,const U u)554 static bool GreaterThan( const T t, const U u ) throw() 555 { 556 // one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller 557 if( u < 0 ) 558 { 559 return SafeIntNoError; 560 } 561 562 // else safe to cast to type T 563 return ( t > (T)u ); 564 } 565 }; 566 567 template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_UnsignedU > 568 { 569 public: GreaterThan(const T t,const U u)570 static bool GreaterThan( const T t, const U u ) throw() 571 { 572 // one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller 573 if( t < 0 ) 574 { 575 return false; 576 } 577 578 // else safe to cast to type U 579 return ( (U)t > u ); 580 } 581 }; 582 583 // Modulus is simpler than comparison, but follows much the same logic 584 // using this set of functions, it can't fail except in a div 0 situation 585 template <typename T, typename U, typename E, int Method = ValidComparison< T, U >::method > class ModulusHelper; 586 587 template <typename T, typename U, typename E> class ModulusHelper <T, U, E, ComparisonMethod_Ok> 588 { 589 public: Modulus(const T & t,const U & u,T & result)590 static SafeIntError Modulus( const T& t, const U& u, T& result ) 591 { 592 if(u == 0) 593 { 594 E::SafeIntOnDivZero(); 595 return SafeIntDivideByZero; 596 } 597 598 // trap corner case 599 #pragma warning(suppress:4127) 600 if( IntTraits< U >::isSigned ) 601 { 602 if(u == -1) 603 { 604 result = 0; 605 return SafeIntNoError; 606 } 607 } 608 609 result = (T)(t % u); 610 return SafeIntNoError; 611 } 612 }; 613 614 template <typename T, typename U, typename E> class ModulusHelper <T, U, E, ComparisonMethod_CastInt> 615 { 616 public: Modulus(const T & t,const U & u,T & result)617 static SafeIntError Modulus( const T& t, const U& u, T& result ) 618 { 619 if(u == 0) 620 { 621 E::SafeIntOnDivZero(); 622 return SafeIntDivideByZero; 623 } 624 625 // trap corner case 626 #pragma warning(suppress:4127) 627 if( IntTraits< U >::isSigned ) 628 { 629 if(u == -1) 630 { 631 result = 0; 632 return SafeIntNoError; 633 } 634 } 635 636 result = (T)(t % u); 637 return SafeIntNoError; 638 } 639 }; 640 641 template <typename T, typename U, typename E> class ModulusHelper <T, U, E, ComparisonMethod_CastInt64> 642 { 643 public: Modulus(const T & t,const U & u,T & result)644 static SafeIntError Modulus( const T& t, const U& u, T& result ) 645 { 646 if(u == 0) 647 { 648 E::SafeIntOnDivZero(); 649 return SafeIntDivideByZero; 650 } 651 652 #pragma warning(suppress:4127) 653 if(IntTraits< U >::isSigned && u == -1) 654 { 655 result = 0; 656 } 657 else 658 { 659 result = (T)((__int64)t % (__int64)u); 660 } 661 662 return SafeIntNoError; 663 } 664 }; 665 666 // T is unsigned __int64, U is any signed int 667 template <typename T, typename U, typename E> class ModulusHelper <T, U, E, ComparisonMethod_UnsignedT> 668 { 669 public: Modulus(const T & t,const U & u,T & result)670 static SafeIntError Modulus( const T& t, const U& u, T& result ) 671 { 672 if(u == 0) 673 { 674 E::SafeIntOnDivZero(); 675 return SafeIntDivideByZero; 676 } 677 678 // u could be negative - if so, need to convert to positive 679 // casts below are always safe due to the way modulus works 680 if(u < 0) 681 { 682 result = (T)(t % AbsValueHelper< U >::Abs(u)); 683 } 684 else 685 { 686 result = (T)(t % u); 687 } 688 689 return SafeIntNoError; 690 } 691 }; 692 693 // U is unsigned __int64, T any signed int 694 template <typename T, typename U, typename E> class ModulusHelper <T, U, E, ComparisonMethod_UnsignedU> 695 { 696 public: Modulus(const T & t,const U & u,T & result)697 static SafeIntError Modulus( const T& t, const U& u, T& result ) 698 { 699 if(u == 0) 700 { 701 E::SafeIntOnDivZero(); 702 return SafeIntDivideByZero; 703 } 704 705 //t could be negative - if so, need to convert to positive 706 if(t < 0) 707 { 708 result = -(T)( AbsValueHelper< T >::Abs( t ) % u ); 709 } 710 else 711 { 712 result = (T)((T)t % u); 713 } 714 715 return SafeIntNoError; 716 } 717 }; 718 719 //core logic to determine method to check multiplication 720 enum MultiplicationState 721 { 722 MultiplicationState_CastInt = 0, // One or both signed, smaller than 32-bit 723 MultiplicationState_CastInt64, // One or both signed, smaller than 64-bit 724 MultiplicationState_CastUint, // Both are unsigned, smaller than 32-bit 725 MultiplicationState_CastUint64, // Both are unsigned, both 32-bit or smaller 726 MultiplicationState_Uint64Uint, // Both are unsigned, lhs 64-bit, rhs 32-bit or smaller 727 MultiplicationState_Uint64Uint64, // Both are unsigned int64 728 MultiplicationState_Uint64Int, // lhs is unsigned int64, rhs int32 729 MultiplicationState_Uint64Int64, // lhs is unsigned int64, rhs signed int64 730 MultiplicationState_UintUint64, // Both are unsigned, lhs 32-bit or smaller, rhs 64-bit 731 MultiplicationState_UintInt64, // lhs unsigned 32-bit or less, rhs int64 732 MultiplicationState_Int64Uint, // lhs int64, rhs unsigned int32 733 MultiplicationState_Int64Int64, // lhs int64, rhs int64 734 MultiplicationState_Int64Int, // lhs int64, rhs int32 735 MultiplicationState_IntUint64, // lhs int, rhs unsigned int64 736 MultiplicationState_IntInt64, // lhs int, rhs int64 737 MultiplicationState_Int64Uint64, // lhs int64, rhs uint64 738 MultiplicationState_Error 739 }; 740 741 template < typename T, typename U > 742 class MultiplicationMethod 743 { 744 public: 745 enum 746 { 747 // unsigned-unsigned 748 method = (IntRegion< T,U >::IntZone_UintLT32_UintLT32 ? MultiplicationState_CastUint : 749 (IntRegion< T,U >::IntZone_Uint32_UintLT64 || 750 IntRegion< T,U >::IntZone_UintLT32_Uint32) ? MultiplicationState_CastUint64 : 751 SafeIntCompare< T,U >::isBothUnsigned && 752 IntTraits< T >::isUint64 && IntTraits< U >::isUint64 ? MultiplicationState_Uint64Uint64 : 753 (IntRegion< T,U >::IntZone_Uint64_Uint) ? MultiplicationState_Uint64Uint : 754 (IntRegion< T,U >::IntZone_UintLT64_Uint64) ? MultiplicationState_UintUint64 : 755 // unsigned-signed 756 (IntRegion< T,U >::IntZone_UintLT32_IntLT32) ? MultiplicationState_CastInt : 757 (IntRegion< T,U >::IntZone_Uint32_IntLT64 || 758 IntRegion< T,U >::IntZone_UintLT32_Int32) ? MultiplicationState_CastInt64 : 759 (IntRegion< T,U >::IntZone_Uint64_Int) ? MultiplicationState_Uint64Int : 760 (IntRegion< T,U >::IntZone_UintLT64_Int64) ? MultiplicationState_UintInt64 : 761 (IntRegion< T,U >::IntZone_Uint64_Int64) ? MultiplicationState_Uint64Int64 : 762 // signed-signed 763 (IntRegion< T,U >::IntZone_IntLT32_IntLT32) ? MultiplicationState_CastInt : 764 (IntRegion< T,U >::IntZone_Int32_IntLT64 || 765 IntRegion< T,U >::IntZone_IntLT32_Int32) ? MultiplicationState_CastInt64 : 766 (IntRegion< T,U >::IntZone_Int64_Int64) ? MultiplicationState_Int64Int64 : 767 (IntRegion< T,U >::IntZone_Int64_Int) ? MultiplicationState_Int64Int : 768 (IntRegion< T,U >::IntZone_IntLT64_Int64) ? MultiplicationState_IntInt64 : 769 // signed-unsigned 770 (IntRegion< T,U >::IntZone_IntLT32_UintLT32) ? MultiplicationState_CastInt : 771 (IntRegion< T,U >::IntZone_Int32_UintLT32 || 772 IntRegion< T,U >::IntZone_IntLT64_Uint32) ? MultiplicationState_CastInt64 : 773 (IntRegion< T,U >::IntZone_Int64_UintLT64) ? MultiplicationState_Int64Uint : 774 (IntRegion< T,U >::IntZone_Int_Uint64) ? MultiplicationState_IntUint64 : 775 (IntRegion< T,U >::IntZone_Int64_Uint64 ? MultiplicationState_Int64Uint64 : 776 MultiplicationState_Error ) ) 777 }; 778 }; 779 780 template <typename T, typename U, typename E, int Method = MultiplicationMethod< T, U >::method > class MultiplicationHelper; 781 782 template < typename T, typename U, typename E > class MultiplicationHelper< T, U, E, MultiplicationState_CastInt> 783 { 784 public: 785 //accepts signed, both less than 32-bit Multiply(const T & t,const U & u,T & ret)786 static SafeIntError Multiply( const T& t, const U& u, T& ret ) 787 { 788 int tmp = t * u; 789 790 if( tmp > IntTraits< T >::maxInt || tmp < IntTraits< T >::minInt ) 791 { 792 E::SafeIntOnOverflow(); 793 return SafeIntArithmeticOverflow; 794 } 795 796 ret = (T)tmp; 797 return SafeIntNoError; 798 } 799 }; 800 801 template < typename T, typename U, typename E > class MultiplicationHelper< T, U, E, MultiplicationState_CastUint > 802 { 803 public: 804 //accepts unsigned, both less than 32-bit Multiply(const T & t,const U & u,T & ret)805 static SafeIntError Multiply( const T& t, const U& u, T& ret ) 806 { 807 unsigned int tmp = t * u; 808 809 if( tmp > IntTraits< T >::maxInt ) 810 { 811 E::SafeIntOnOverflow(); 812 return SafeIntArithmeticOverflow; 813 } 814 815 ret = (T)tmp; 816 return SafeIntNoError; 817 } 818 }; 819 820 template < typename T, typename U, typename E > class MultiplicationHelper< T, U, E, MultiplicationState_CastInt64> 821 { 822 public: 823 //mixed signed or both signed where at least one argument is 32-bit, and both a 32-bit or less Multiply(const T & t,const U & u,T & ret)824 static SafeIntError Multiply( const T& t, const U& u, T& ret ) 825 { 826 __int64 tmp = (__int64)t * (__int64)u; 827 828 if(tmp > (__int64)IntTraits< T >::maxInt || tmp < (__int64)IntTraits< T >::minInt) 829 { 830 E::SafeIntOnOverflow(); 831 return SafeIntArithmeticOverflow; 832 } 833 834 ret = (T)tmp; 835 return SafeIntNoError; 836 } 837 }; 838 839 template < typename T, typename U, typename E > class MultiplicationHelper< T, U, E, MultiplicationState_CastUint64> 840 { 841 public: 842 //both unsigned where at least one argument is 32-bit, and both are 32-bit or less Multiply(const T & t,const U & u,T & ret)843 static SafeIntError Multiply( const T& t, const U& u, T& ret ) 844 { 845 unsigned __int64 tmp = (unsigned __int64)t * (unsigned __int64)u; 846 847 if(tmp > (unsigned __int64)IntTraits< T >::maxInt) 848 { 849 E::SafeIntOnOverflow(); 850 return SafeIntArithmeticOverflow; 851 } 852 853 ret = (T)tmp; 854 return SafeIntNoError; 855 } 856 }; 857 858 // T = left arg and return type 859 // U = right arg 860 template < typename T, typename U, typename E > class LargeIntRegMultiply; 861 862 template< typename E > class LargeIntRegMultiply< unsigned __int64, unsigned __int64, E > 863 { 864 public: RegMultiply(const unsigned __int64 & a,const unsigned __int64 & b,unsigned __int64 & ret)865 static SafeIntError RegMultiply( const unsigned __int64& a, const unsigned __int64& b, unsigned __int64& ret ) 866 { 867 unsigned __int32 aHigh, aLow, bHigh, bLow; 868 869 // Consider that a*b can be broken up into: 870 // (aHigh * 2^32 + aLow) * (bHigh * 2^32 + bLow) 871 // => (aHigh * bHigh * 2^64) + (aLow * bHigh * 2^32) + (aHigh * bLow * 2^32) + (aLow * bLow) 872 // Note - same approach applies for 128 bit math on a 64-bit system 873 874 aHigh = (unsigned __int32)(a >> 32); 875 aLow = (unsigned __int32)a; 876 bHigh = (unsigned __int32)(b >> 32); 877 bLow = (unsigned __int32)b; 878 879 ret = 0; 880 881 if(aHigh == 0) 882 { 883 if(bHigh != 0) 884 { 885 ret = (unsigned __int64)aLow * (unsigned __int64)bHigh; 886 } 887 } 888 else if(bHigh == 0) 889 { 890 if(aHigh != 0) 891 { 892 ret = (unsigned __int64)aHigh * (unsigned __int64)bLow; 893 } 894 } 895 else 896 { 897 E::SafeIntOnOverflow(); 898 return SafeIntArithmeticOverflow; 899 } 900 901 if(ret != 0) 902 { 903 unsigned __int64 tmp; 904 905 if((unsigned __int32)(ret >> 32) != 0) 906 { 907 E::SafeIntOnOverflow(); 908 return SafeIntArithmeticOverflow; 909 } 910 911 ret <<= 32; 912 tmp = (unsigned __int64)aLow * (unsigned __int64)bLow; 913 ret += tmp; 914 915 if(ret < tmp) 916 { 917 E::SafeIntOnOverflow(); 918 return SafeIntArithmeticOverflow; 919 } 920 921 return SafeIntNoError; 922 } 923 924 ret = (unsigned __int64)aLow * (unsigned __int64)bLow; 925 return SafeIntNoError; 926 } 927 }; 928 929 template< typename E > class LargeIntRegMultiply< unsigned __int64, unsigned __int32, E > 930 { 931 public: RegMultiply(const unsigned __int64 & a,unsigned __int32 b,unsigned __int64 & ret)932 static SafeIntError RegMultiply( const unsigned __int64& a, unsigned __int32 b, unsigned __int64& ret ) 933 { 934 unsigned __int32 aHigh, aLow; 935 936 // Consider that a*b can be broken up into: 937 // (aHigh * 2^32 + aLow) * b 938 // => (aHigh * b * 2^32) + (aLow * b) 939 940 aHigh = (unsigned __int32)(a >> 32); 941 aLow = (unsigned __int32)a; 942 943 ret = 0; 944 945 if(aHigh != 0) 946 { 947 ret = (unsigned __int64)aHigh * (unsigned __int64)b; 948 949 unsigned __int64 tmp; 950 951 if((unsigned __int32)(ret >> 32) != 0) 952 { 953 E::SafeIntOnOverflow(); 954 return SafeIntArithmeticOverflow; 955 } 956 957 ret <<= 32; 958 tmp = (unsigned __int64)aLow * (unsigned __int64)b; 959 ret += tmp; 960 961 if(ret < tmp) 962 { 963 E::SafeIntOnOverflow(); 964 return SafeIntArithmeticOverflow; 965 } 966 967 return SafeIntNoError; 968 } 969 970 ret = (unsigned __int64)aLow * (unsigned __int64)b; 971 return SafeIntNoError; 972 } 973 }; 974 975 template< typename E > class LargeIntRegMultiply< unsigned __int64, signed __int32, E > 976 { 977 public: RegMultiply(const unsigned __int64 & a,signed __int32 b,unsigned __int64 & ret)978 static SafeIntError RegMultiply( const unsigned __int64& a, signed __int32 b, unsigned __int64& ret ) 979 { 980 if( b < 0 && a != 0 ) 981 { 982 E::SafeIntOnOverflow(); 983 return SafeIntArithmeticOverflow; 984 } 985 986 return LargeIntRegMultiply< unsigned __int64, unsigned __int32, E >::RegMultiply(a, (unsigned __int32)b, ret); 987 } 988 }; 989 990 template< typename E > class LargeIntRegMultiply< unsigned __int64, signed __int64, E > 991 { 992 public: RegMultiply(const unsigned __int64 & a,signed __int64 b,unsigned __int64 & ret)993 static SafeIntError RegMultiply( const unsigned __int64& a, signed __int64 b, unsigned __int64& ret ) 994 { 995 if( b < 0 && a != 0 ) 996 { 997 E::SafeIntOnOverflow(); 998 return SafeIntArithmeticOverflow; 999 } 1000 1001 return LargeIntRegMultiply< unsigned __int64, unsigned __int64, E >::RegMultiply(a, (unsigned __int64)b, ret); 1002 } 1003 }; 1004 1005 template< typename E > class LargeIntRegMultiply< signed __int32, unsigned __int64, E > 1006 { 1007 public: RegMultiply(signed __int32 a,const unsigned __int64 & b,signed __int32 & ret)1008 static SafeIntError RegMultiply( signed __int32 a, const unsigned __int64& b, signed __int32& ret ) 1009 { 1010 unsigned __int32 bHigh, bLow; 1011 bool fIsNegative = false; 1012 1013 // Consider that a*b can be broken up into: 1014 // (aHigh * 2^32 + aLow) * (bHigh * 2^32 + bLow) 1015 // => (aHigh * bHigh * 2^64) + (aLow * bHigh * 2^32) + (aHigh * bLow * 2^32) + (aLow * bLow) 1016 1017 bHigh = (unsigned __int32)(b >> 32); 1018 bLow = (unsigned __int32)b; 1019 1020 ret = 0; 1021 1022 if(bHigh != 0 && a != 0) 1023 { 1024 E::SafeIntOnOverflow(); 1025 return SafeIntArithmeticOverflow; 1026 } 1027 1028 if( a < 0 ) 1029 { 1030 a = -a; 1031 fIsNegative = true; 1032 } 1033 1034 unsigned __int64 tmp = (unsigned __int32)a * (unsigned __int64)bLow; 1035 1036 1037 if( !fIsNegative ) 1038 { 1039 if( tmp <= (unsigned __int64)IntTraits< signed __int32 >::maxInt ) 1040 { 1041 ret = (signed __int32)tmp; 1042 return SafeIntNoError; 1043 } 1044 } 1045 else 1046 { 1047 if( tmp <= (unsigned __int64)IntTraits< signed __int32 >::maxInt+1 ) 1048 { 1049 ret = -( (signed __int32)tmp ); 1050 return SafeIntNoError; 1051 } 1052 } 1053 1054 E::SafeIntOnOverflow(); 1055 return SafeIntArithmeticOverflow; 1056 } 1057 }; 1058 1059 template < typename E > class LargeIntRegMultiply< unsigned __int32, unsigned __int64, E > 1060 { 1061 public: RegMultiply(unsigned __int32 a,const unsigned __int64 & b,unsigned __int32 & ret)1062 static SafeIntError RegMultiply( unsigned __int32 a, const unsigned __int64& b, unsigned __int32& ret ) 1063 { 1064 // Consider that a*b can be broken up into: 1065 // (bHigh * 2^32 + bLow) * a 1066 // => (bHigh * a * 2^32) + (bLow * a) 1067 // In this case, the result must fit into 32-bits 1068 // If bHigh != 0 && a != 0, immediate error. 1069 1070 if( (unsigned __int32)(b >> 32) != 0 && a != 0 ) 1071 { 1072 E::SafeIntOnOverflow(); 1073 return SafeIntArithmeticOverflow; 1074 } 1075 1076 unsigned __int64 tmp = b * (unsigned __int64)a; 1077 1078 if( (unsigned __int32)(tmp >> 32) != 0 ) // overflow 1079 { 1080 E::SafeIntOnOverflow(); 1081 return SafeIntArithmeticOverflow; 1082 } 1083 1084 ret = (unsigned __int32)tmp; 1085 return SafeIntNoError; 1086 } 1087 }; 1088 1089 template < typename E > class LargeIntRegMultiply< unsigned __int32, signed __int64, E > 1090 { 1091 public: RegMultiply(unsigned __int32 a,const signed __int64 & b,unsigned __int32 & ret)1092 static SafeIntError RegMultiply( unsigned __int32 a, const signed __int64& b, unsigned __int32& ret ) 1093 { 1094 if( b < 0 && a != 0 ) 1095 { 1096 E::SafeIntOnOverflow(); 1097 return SafeIntArithmeticOverflow; 1098 } 1099 1100 return LargeIntRegMultiply< unsigned __int32, unsigned __int64, E >::RegMultiply( a, (unsigned __int64)b, ret ); 1101 } 1102 }; 1103 1104 template < typename E > class LargeIntRegMultiply< signed __int64, signed __int64, E > 1105 { 1106 public: RegMultiply(const signed __int64 & a,const signed __int64 & b,signed __int64 & ret)1107 static SafeIntError RegMultiply( const signed __int64& a, const signed __int64& b, signed __int64& ret ) 1108 { 1109 bool aNegative = false; 1110 bool bNegative = false; 1111 1112 unsigned __int64 tmp; 1113 __int64 a1 = a; 1114 __int64 b1 = b; 1115 1116 if( a1 < 0 ) 1117 { 1118 aNegative = true; 1119 a1 = -a1; 1120 } 1121 1122 if( b1 < 0 ) 1123 { 1124 bNegative = true; 1125 b1 = -b1; 1126 } 1127 1128 if( LargeIntRegMultiply< unsigned __int64, unsigned __int64, E >:: 1129 RegMultiply( (unsigned __int64)a1, (unsigned __int64)b1, tmp ) == SafeIntNoError ) 1130 { 1131 // The unsigned multiplication didn't overflow 1132 if( aNegative ^ bNegative ) 1133 { 1134 // Result must be negative 1135 if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt ) 1136 { 1137 ret = -(signed __int64)tmp; 1138 return SafeIntNoError; 1139 } 1140 } 1141 else 1142 { 1143 // Result must be positive 1144 if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt ) 1145 { 1146 ret = (signed __int64)tmp; 1147 return SafeIntNoError; 1148 } 1149 } 1150 } 1151 1152 E::SafeIntOnOverflow(); 1153 return SafeIntArithmeticOverflow; 1154 } 1155 }; 1156 1157 template < typename E > class LargeIntRegMultiply< signed __int64, unsigned __int32, E > 1158 { 1159 public: RegMultiply(const signed __int64 & a,unsigned __int32 b,signed __int64 & ret)1160 static SafeIntError RegMultiply( const signed __int64& a, unsigned __int32 b, signed __int64& ret ) 1161 { 1162 bool aNegative = false; 1163 unsigned __int64 tmp; 1164 __int64 a1 = a; 1165 1166 if( a1 < 0 ) 1167 { 1168 aNegative = true; 1169 a1 = -a1; 1170 } 1171 1172 if( LargeIntRegMultiply< unsigned __int64, unsigned __int32, E >::RegMultiply( (unsigned __int64)a1, b, tmp ) == SafeIntNoError ) 1173 { 1174 // The unsigned multiplication didn't overflow 1175 if( aNegative ) 1176 { 1177 // Result must be negative 1178 if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt ) 1179 { 1180 ret = -(signed __int64)tmp; 1181 return SafeIntNoError; 1182 } 1183 } 1184 else 1185 { 1186 // Result must be positive 1187 if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt ) 1188 { 1189 ret = (signed __int64)tmp; 1190 return SafeIntNoError; 1191 } 1192 } 1193 } 1194 1195 E::SafeIntOnOverflow(); 1196 return SafeIntArithmeticOverflow; 1197 } 1198 }; 1199 1200 template < typename E > class LargeIntRegMultiply< signed __int64, signed __int32, E > 1201 { 1202 public: RegMultiply(const signed __int64 & a,signed __int32 b,signed __int64 & ret)1203 static SafeIntError RegMultiply( const signed __int64& a, signed __int32 b, signed __int64& ret ) 1204 { 1205 bool aNegative = false; 1206 bool bNegative = false; 1207 1208 unsigned __int64 tmp; 1209 __int64 a1 = a; 1210 __int64 b1 = b; 1211 1212 if( a1 < 0 ) 1213 { 1214 aNegative = true; 1215 a1 = -a1; 1216 } 1217 1218 if( b1 < 0 ) 1219 { 1220 bNegative = true; 1221 b1 = -b1; 1222 } 1223 1224 if( LargeIntRegMultiply< unsigned __int64, unsigned __int32, E >:: 1225 RegMultiply( (unsigned __int64)a1, (unsigned __int32)b1, tmp ) == SafeIntNoError ) 1226 { 1227 // The unsigned multiplication didn't overflow 1228 if( aNegative ^ bNegative ) 1229 { 1230 // Result must be negative 1231 if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt ) 1232 { 1233 ret = -(signed __int64)tmp; 1234 return SafeIntNoError; 1235 } 1236 } 1237 else 1238 { 1239 // Result must be positive 1240 if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt ) 1241 { 1242 ret = (signed __int64)tmp; 1243 return SafeIntNoError; 1244 } 1245 } 1246 } 1247 1248 E::SafeIntOnOverflow(); 1249 return SafeIntArithmeticOverflow; 1250 } 1251 }; 1252 1253 template < typename E > class LargeIntRegMultiply< signed __int32, signed __int64, E > 1254 { 1255 public: RegMultiply(signed __int32 a,const signed __int64 & b,signed __int32 & ret)1256 static SafeIntError RegMultiply( signed __int32 a, const signed __int64& b, signed __int32& ret ) 1257 { 1258 bool aNegative = false; 1259 bool bNegative = false; 1260 1261 unsigned __int32 tmp; 1262 __int64 b1 = b; 1263 1264 if( a < 0 ) 1265 { 1266 aNegative = true; 1267 a = -a; 1268 } 1269 1270 if( b1 < 0 ) 1271 { 1272 bNegative = true; 1273 b1 = -b1; 1274 } 1275 1276 if( LargeIntRegMultiply< unsigned __int32, unsigned __int64, E >:: 1277 RegMultiply( (unsigned __int32)a, (unsigned __int64)b1, tmp ) == SafeIntNoError ) 1278 { 1279 // The unsigned multiplication didn't overflow 1280 if( aNegative ^ bNegative ) 1281 { 1282 // Result must be negative 1283 if( tmp <= (unsigned __int32)IntTraits< signed __int32 >::minInt ) 1284 { 1285 #pragma warning(suppress:4146) 1286 ret = -tmp; 1287 return SafeIntNoError; 1288 } 1289 } 1290 else 1291 { 1292 // Result must be positive 1293 if( tmp <= (unsigned __int32)IntTraits< signed __int32 >::maxInt ) 1294 { 1295 ret = (signed __int32)tmp; 1296 return SafeIntNoError; 1297 } 1298 } 1299 } 1300 1301 E::SafeIntOnOverflow(); 1302 return SafeIntArithmeticOverflow; 1303 } 1304 }; 1305 1306 template < typename E > class LargeIntRegMultiply< signed __int64, unsigned __int64, E > 1307 { 1308 public: RegMultiply(const signed __int64 & a,const unsigned __int64 & b,signed __int64 & ret)1309 static SafeIntError RegMultiply( const signed __int64& a, const unsigned __int64& b, signed __int64& ret ) 1310 { 1311 bool aNegative = false; 1312 1313 unsigned __int64 tmp; 1314 __int64 a1 = a; 1315 1316 if( a1 < 0 ) 1317 { 1318 aNegative = true; 1319 a1 = -a1; 1320 } 1321 1322 if( LargeIntRegMultiply< unsigned __int64, unsigned __int64, E >:: 1323 RegMultiply( (unsigned __int64)a1, (unsigned __int64)b, tmp ) == SafeIntNoError ) 1324 { 1325 // The unsigned multiplication didn't overflow 1326 if( aNegative ) 1327 { 1328 // Result must be negative 1329 if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt ) 1330 { 1331 ret = -((signed __int64)tmp); 1332 return SafeIntNoError; 1333 } 1334 } 1335 else 1336 { 1337 // Result must be positive 1338 if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt ) 1339 { 1340 ret = (signed __int64)tmp; 1341 return SafeIntNoError; 1342 } 1343 } 1344 } 1345 1346 E::SafeIntOnOverflow(); 1347 return SafeIntArithmeticOverflow; 1348 } 1349 }; 1350 1351 template < typename E > class MultiplicationHelper< unsigned __int64, unsigned __int64, E, MultiplicationState_Uint64Uint64 > 1352 { 1353 public: Multiply(const unsigned __int64 & t,const unsigned __int64 & u,unsigned __int64 & ret)1354 static SafeIntError Multiply( const unsigned __int64& t, const unsigned __int64& u, unsigned __int64& ret ) 1355 { 1356 return LargeIntRegMultiply< unsigned __int64, unsigned __int64, E >::RegMultiply( t, u, ret ); 1357 } 1358 }; 1359 1360 template < typename U, typename E > class MultiplicationHelper<unsigned __int64, U, E, MultiplicationState_Uint64Uint > 1361 { 1362 public: 1363 //U is any unsigned int 32-bit or less Multiply(const unsigned __int64 & t,const U & u,unsigned __int64 & ret)1364 static SafeIntError Multiply( const unsigned __int64& t, const U& u, unsigned __int64& ret ) 1365 { 1366 return LargeIntRegMultiply< unsigned __int64, unsigned __int32, E >::RegMultiply( t, (unsigned __int32)u, ret ); 1367 } 1368 }; 1369 1370 // converse of the previous function 1371 template < typename T, typename E > class MultiplicationHelper< T, unsigned __int64, E, MultiplicationState_UintUint64 > 1372 { 1373 public: 1374 // T is any unsigned int up to 32-bit Multiply(const T & t,const unsigned __int64 & u,T & ret)1375 static SafeIntError Multiply( const T& t, const unsigned __int64& u, T& ret ) 1376 { 1377 unsigned __int32 tmp; 1378 1379 if( LargeIntRegMultiply< unsigned __int32, unsigned __int64, E >::RegMultiply( t, u, tmp ) == SafeIntNoError && 1380 SafeCastHelper< T, unsigned __int32, E >::Cast(tmp, ret) == SafeIntNoError ) 1381 { 1382 return SafeIntNoError; 1383 } 1384 1385 E::SafeIntOnOverflow(); 1386 return SafeIntArithmeticOverflow; 1387 } 1388 }; 1389 1390 template < typename U, typename E > class MultiplicationHelper< unsigned __int64, U, E, MultiplicationState_Uint64Int > 1391 { 1392 public: 1393 //U is any signed int, up to 64-bit Multiply(const unsigned __int64 & t,const U & u,unsigned __int64 & ret)1394 static SafeIntError Multiply(const unsigned __int64& t, const U& u, unsigned __int64& ret) 1395 { 1396 return LargeIntRegMultiply< unsigned __int64, signed __int32, E >::RegMultiply(t, (signed __int32)u, ret); 1397 } 1398 }; 1399 1400 template < typename E > class MultiplicationHelper<unsigned __int64, __int64, E, MultiplicationState_Uint64Int64 > 1401 { 1402 public: Multiply(const unsigned __int64 & t,const __int64 & u,unsigned __int64 & ret)1403 static SafeIntError Multiply(const unsigned __int64& t, const __int64& u, unsigned __int64& ret) 1404 { 1405 return LargeIntRegMultiply< unsigned __int64, __int64, E >::RegMultiply(t, u, ret); 1406 } 1407 }; 1408 1409 template < typename T, typename E > class MultiplicationHelper< T, __int64, E, MultiplicationState_UintInt64 > 1410 { 1411 public: 1412 //T is unsigned up to 32-bit Multiply(const T & t,const __int64 & u,T & ret)1413 static SafeIntError Multiply( const T& t, const __int64& u, T& ret ) 1414 { 1415 unsigned __int32 tmp; 1416 1417 if( LargeIntRegMultiply< unsigned __int32, __int64, E >::RegMultiply( (unsigned __int32)t, u, tmp ) == SafeIntNoError && 1418 SafeCastHelper< T, unsigned __int32, E >::Cast( tmp, ret ) == SafeIntNoError ) 1419 { 1420 return SafeIntNoError; 1421 } 1422 1423 E::SafeIntOnOverflow(); 1424 return SafeIntArithmeticOverflow; 1425 } 1426 }; 1427 1428 template < typename U, typename E > class MultiplicationHelper<__int64, U, E, MultiplicationState_Int64Uint > 1429 { 1430 public: 1431 //U is unsigned up to 32-bit Multiply(const __int64 & t,const U & u,__int64 & ret)1432 static SafeIntError Multiply( const __int64& t, const U& u, __int64& ret ) 1433 { 1434 return LargeIntRegMultiply< __int64, unsigned __int32, E >::RegMultiply( t, (unsigned __int32)u, ret ); 1435 } 1436 }; 1437 1438 template < typename E > class MultiplicationHelper<__int64, __int64, E, MultiplicationState_Int64Int64 > 1439 { 1440 public: Multiply(const __int64 & t,const __int64 & u,__int64 & ret)1441 static SafeIntError Multiply( const __int64& t, const __int64& u, __int64& ret ) 1442 { 1443 return LargeIntRegMultiply< __int64, __int64, E >::RegMultiply( t, u, ret ); 1444 } 1445 }; 1446 1447 template < typename U, typename E > class MultiplicationHelper<__int64, U, E, MultiplicationState_Int64Int> 1448 { 1449 public: 1450 //U is signed up to 32-bit Multiply(const __int64 & t,U u,__int64 & ret)1451 static SafeIntError Multiply( const __int64& t, U u, __int64& ret ) 1452 { 1453 return LargeIntRegMultiply< __int64, __int32, E >::RegMultiply( t, (__int32)u, ret ); 1454 } 1455 }; 1456 1457 template < typename T, typename E > class MultiplicationHelper< T, unsigned __int64, E, MultiplicationState_IntUint64 > 1458 { 1459 public: 1460 //T is signed up to 32-bit Multiply(T t,const unsigned __int64 & u,T & ret)1461 static SafeIntError Multiply(T t, const unsigned __int64& u, T& ret) 1462 { 1463 __int32 tmp; 1464 1465 if( LargeIntRegMultiply< __int32, unsigned __int64, E >::RegMultiply( (__int32)t, u, tmp ) == SafeIntNoError && 1466 SafeCastHelper< T, __int32, E >::Cast( tmp, ret ) == SafeIntNoError ) 1467 { 1468 return SafeIntNoError; 1469 } 1470 1471 E::SafeIntOnOverflow(); 1472 return SafeIntArithmeticOverflow; 1473 } 1474 }; 1475 1476 template < typename E > class MultiplicationHelper<__int64, unsigned __int64, E, MultiplicationState_Int64Uint64> 1477 { 1478 public: 1479 //U is signed up to 32-bit Multiply(const __int64 & t,const unsigned __int64 & u,__int64 & ret)1480 static SafeIntError Multiply( const __int64& t, const unsigned __int64& u, __int64& ret ) 1481 { 1482 return LargeIntRegMultiply< __int64, unsigned __int64, E >::RegMultiply( t, u, ret ); 1483 } 1484 }; 1485 1486 template < typename T, typename E > class MultiplicationHelper< T, __int64, E, MultiplicationState_IntInt64> 1487 { 1488 public: 1489 //T is signed, up to 32-bit Multiply(T t,const __int64 & u,T & ret)1490 static SafeIntError Multiply( T t, const __int64& u, T& ret ) 1491 { 1492 __int32 tmp; 1493 1494 if( LargeIntRegMultiply< __int32, __int64, E >::RegMultiply( (__int32)t, u, tmp ) == SafeIntNoError && 1495 SafeCastHelper< T, __int32, E >::Cast( tmp, ret ) == SafeIntNoError ) 1496 { 1497 return SafeIntNoError; 1498 } 1499 1500 E::SafeIntOnOverflow(); 1501 return SafeIntArithmeticOverflow; 1502 } 1503 }; 1504 1505 enum DivisionState 1506 { 1507 DivisionState_OK, 1508 DivisionState_UnsignedSigned, 1509 DivisionState_SignedUnsigned32, 1510 DivisionState_SignedUnsigned64, 1511 DivisionState_SignedUnsigned, 1512 DivisionState_SignedSigned 1513 }; 1514 1515 template < typename T, typename U > class DivisionMethod 1516 { 1517 public: 1518 enum 1519 { 1520 method = (SafeIntCompare< T, U >::isBothUnsigned ? DivisionState_OK : 1521 (!IntTraits< T >::isSigned && IntTraits< U >::isSigned) ? DivisionState_UnsignedSigned : 1522 (IntTraits< T >::isSigned && 1523 IntTraits< U >::isUint32 && 1524 IntTraits< T >::isLT64Bit) ? DivisionState_SignedUnsigned32 : 1525 (IntTraits< T >::isSigned && IntTraits< U >::isUint64) ? DivisionState_SignedUnsigned64 : 1526 (IntTraits< T >::isSigned && !IntTraits< U >::isSigned) ? DivisionState_SignedUnsigned : 1527 DivisionState_SignedSigned) 1528 }; 1529 }; 1530 1531 template < typename T, typename U, typename E, int Method = DivisionMethod< T, U >::method > class DivisionHelper; 1532 1533 template < typename T, typename U, typename E > class DivisionHelper< T, U, E, DivisionState_OK > 1534 { 1535 public: Divide(const T & t,const U & u,T & result)1536 static SafeIntError Divide( const T& t, const U& u, T& result ) 1537 { 1538 if( u == 0 ) 1539 { 1540 E::SafeIntOnDivZero(); 1541 return SafeIntDivideByZero; 1542 } 1543 1544 result = (T)( t/u ); 1545 return SafeIntNoError; 1546 } 1547 }; 1548 1549 template < typename T, typename U, typename E > class DivisionHelper< T, U, E, DivisionState_UnsignedSigned> 1550 { 1551 public: Divide(const T & t,const U & u,T & result)1552 static SafeIntError Divide( const T& t, const U& u, T& result ) 1553 { 1554 if( u > 0 ) 1555 { 1556 result = (T)( t/u ); 1557 return SafeIntNoError; 1558 } 1559 1560 if( u == 0 ) 1561 { 1562 E::SafeIntOnDivZero(); 1563 return SafeIntDivideByZero; 1564 } 1565 1566 // it is always an error to try and divide an unsigned number by a negative signed number 1567 // unless u is bigger than t 1568 if( AbsValueHelper< U >::Abs( u ) > t ) 1569 { 1570 result = 0; 1571 return SafeIntNoError; 1572 } 1573 1574 E::SafeIntOnOverflow(); 1575 return SafeIntArithmeticOverflow; 1576 } 1577 }; 1578 1579 template < typename T, typename U, typename E > class DivisionHelper< T, U, E, DivisionState_SignedUnsigned32 > 1580 { 1581 public: Divide(const T & t,const U & u,T & result)1582 static SafeIntError Divide( const T& t, const U& u, T& result ) 1583 { 1584 if( u == 0 ) 1585 { 1586 E::SafeIntOnDivZero(); 1587 return SafeIntDivideByZero; 1588 } 1589 1590 // Test for t > 0 1591 // If t < 0, must explicitly upcast, or implicit upcast to ulong will cause errors 1592 // As it turns out, 32-bit division is about twice as fast, which justifies the extra conditional 1593 if( t > 0 ) 1594 result = (T)( t/u ); 1595 else 1596 result = (T)( (__int64)t/(__int64)u ); 1597 1598 return SafeIntNoError; 1599 } 1600 }; 1601 1602 template < typename T, typename E > class DivisionHelper< T, unsigned __int64, E, DivisionState_SignedUnsigned64 > 1603 { 1604 public: Divide(const T & t,const unsigned __int64 & u,T & result)1605 static SafeIntError Divide( const T& t, const unsigned __int64& u, T& result ) 1606 { 1607 if( u == 0 ) 1608 { 1609 E::SafeIntOnDivZero(); 1610 return SafeIntDivideByZero; 1611 } 1612 1613 if( u <= (unsigned __int64)IntTraits< T >::maxInt ) 1614 { 1615 // Else u can safely be cast to T 1616 #pragma warning(suppress:4127) 1617 if( sizeof( T ) < sizeof( __int64 ) ) 1618 result = (T)( (int)t/(int)u ); 1619 else 1620 result = (T)((__int64)t/(__int64)u); 1621 } 1622 else // Corner case 1623 if( t == IntTraits< T >::minInt && u == (unsigned __int64)IntTraits< T >::minInt ) 1624 { 1625 // Min int divided by its own magnitude is -1 1626 result = -1; 1627 } 1628 else 1629 { 1630 result = 0; 1631 } 1632 return SafeIntNoError; 1633 } 1634 }; 1635 1636 template < typename T, typename U, typename E > class DivisionHelper< T, U, E, DivisionState_SignedUnsigned> 1637 { 1638 public: 1639 // T is any signed, U is unsigned and smaller than 32-bit 1640 // In this case, standard operator casting is correct Divide(const T & t,const U & u,T & result)1641 static SafeIntError Divide( const T& t, const U& u, T& result ) 1642 { 1643 if( u == 0 ) 1644 { 1645 E::SafeIntOnDivZero(); 1646 return SafeIntDivideByZero; 1647 } 1648 1649 result = (T)( t/u ); 1650 return SafeIntNoError; 1651 } 1652 }; 1653 1654 template < typename T, typename U, typename E > class DivisionHelper< T, U, E, DivisionState_SignedSigned> 1655 { 1656 public: Divide(const T & t,const U & u,T & result)1657 static SafeIntError Divide( const T& t, const U& u, T& result ) 1658 { 1659 if( u == 0 ) 1660 { 1661 E::SafeIntOnDivZero(); 1662 return SafeIntDivideByZero; 1663 } 1664 1665 // Must test for corner case 1666 if( t == IntTraits< T >::minInt && u == -1 ) 1667 { 1668 E::SafeIntOnOverflow(); 1669 return SafeIntArithmeticOverflow; 1670 } 1671 1672 result = (T)( t/u ); 1673 return SafeIntNoError; 1674 } 1675 }; 1676 1677 enum AdditionState 1678 { 1679 AdditionState_CastIntCheckMax, 1680 AdditionState_CastUintCheckOverflow, 1681 AdditionState_CastUintCheckOverflowMax, 1682 AdditionState_CastUint64CheckOverflow, 1683 AdditionState_CastUint64CheckOverflowMax, 1684 AdditionState_CastIntCheckMinMax, 1685 AdditionState_CastInt64CheckMinMax, 1686 AdditionState_CastInt64CheckMax, 1687 AdditionState_CastUint64CheckMinMax, 1688 AdditionState_CastUint64CheckMinMax2, 1689 AdditionState_CastInt64CheckOverflow, 1690 AdditionState_CastInt64CheckOverflowMinMax, 1691 AdditionState_CastInt64CheckOverflowMax, 1692 AdditionState_ManualCheckInt64Uint64, 1693 AdditionState_ManualCheck, 1694 AdditionState_Error 1695 }; 1696 1697 template< typename T, typename U > 1698 class AdditionMethod 1699 { 1700 public: 1701 enum 1702 { 1703 //unsigned-unsigned 1704 method = (IntRegion< T,U >::IntZone_UintLT32_UintLT32 ? AdditionState_CastIntCheckMax : 1705 (IntRegion< T,U >::IntZone_Uint32_UintLT64) ? AdditionState_CastUintCheckOverflow : 1706 (IntRegion< T,U >::IntZone_UintLT32_Uint32) ? AdditionState_CastUintCheckOverflowMax : 1707 (IntRegion< T,U >::IntZone_Uint64_Uint) ? AdditionState_CastUint64CheckOverflow : 1708 (IntRegion< T,U >::IntZone_UintLT64_Uint64) ? AdditionState_CastUint64CheckOverflowMax : 1709 //unsigned-signed 1710 (IntRegion< T,U >::IntZone_UintLT32_IntLT32) ? AdditionState_CastIntCheckMinMax : 1711 (IntRegion< T,U >::IntZone_Uint32_IntLT64 || 1712 IntRegion< T,U >::IntZone_UintLT32_Int32) ? AdditionState_CastInt64CheckMinMax : 1713 (IntRegion< T,U >::IntZone_Uint64_Int || 1714 IntRegion< T,U >::IntZone_Uint64_Int64) ? AdditionState_CastUint64CheckMinMax : 1715 (IntRegion< T,U >::IntZone_UintLT64_Int64) ? AdditionState_CastUint64CheckMinMax2 : 1716 //signed-signed 1717 (IntRegion< T,U >::IntZone_IntLT32_IntLT32) ? AdditionState_CastIntCheckMinMax : 1718 (IntRegion< T,U >::IntZone_Int32_IntLT64 || 1719 IntRegion< T,U >::IntZone_IntLT32_Int32) ? AdditionState_CastInt64CheckMinMax : 1720 (IntRegion< T,U >::IntZone_Int64_Int || 1721 IntRegion< T,U >::IntZone_Int64_Int64) ? AdditionState_CastInt64CheckOverflow : 1722 (IntRegion< T,U >::IntZone_IntLT64_Int64) ? AdditionState_CastInt64CheckOverflowMinMax : 1723 //signed-unsigned 1724 (IntRegion< T,U >::IntZone_IntLT32_UintLT32) ? AdditionState_CastIntCheckMax : 1725 (IntRegion< T,U >::IntZone_Int32_UintLT32 || 1726 IntRegion< T,U >::IntZone_IntLT64_Uint32) ? AdditionState_CastInt64CheckMax : 1727 (IntRegion< T,U >::IntZone_Int64_UintLT64) ? AdditionState_CastInt64CheckOverflowMax : 1728 (IntRegion< T,U >::IntZone_Int64_Uint64) ? AdditionState_ManualCheckInt64Uint64 : 1729 (IntRegion< T,U >::IntZone_Int_Uint64) ? AdditionState_ManualCheck : 1730 AdditionState_Error) 1731 }; 1732 }; 1733 1734 template < typename T, typename U, typename E, int Method = AdditionMethod< T, U >::method > class AdditionHelper; 1735 1736 template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastIntCheckMax > 1737 { 1738 public: Addition(const T & lhs,const U & rhs,T & result)1739 static SafeIntError Addition( const T& lhs, const U& rhs, T& result ) 1740 { 1741 //16-bit or less unsigned addition 1742 __int32 tmp = lhs + rhs; 1743 1744 if( tmp <= (__int32)IntTraits< T >::maxInt ) 1745 { 1746 result = (T)tmp; 1747 return SafeIntNoError; 1748 } 1749 1750 E::SafeIntOnOverflow(); 1751 return SafeIntArithmeticOverflow; 1752 } 1753 }; 1754 1755 template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastUintCheckOverflow > 1756 { 1757 public: Addition(const T & lhs,const U & rhs,T & result)1758 static SafeIntError Addition( const T& lhs, const U& rhs, T& result ) 1759 { 1760 // 32-bit or less - both are unsigned 1761 unsigned __int32 tmp = (unsigned __int32)lhs + (unsigned __int32)rhs; 1762 1763 //we added didn't get smaller 1764 if( tmp >= lhs ) 1765 { 1766 result = (T)tmp; 1767 return SafeIntNoError; 1768 } 1769 E::SafeIntOnOverflow(); 1770 return SafeIntArithmeticOverflow; 1771 } 1772 }; 1773 1774 template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastUintCheckOverflowMax> 1775 { 1776 public: Addition(const T & lhs,const U & rhs,T & result)1777 static SafeIntError Addition( const T& lhs, const U& rhs, T& result ) 1778 { 1779 // 32-bit or less - both are unsigned 1780 unsigned __int32 tmp = (unsigned __int32)lhs + (unsigned __int32)rhs; 1781 1782 // We added and it didn't get smaller or exceed maxInt 1783 if( tmp >= lhs && tmp <= IntTraits< T >::maxInt ) 1784 { 1785 result = (T)tmp; 1786 return SafeIntNoError; 1787 } 1788 E::SafeIntOnOverflow(); 1789 return SafeIntArithmeticOverflow; 1790 } 1791 }; 1792 1793 template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastUint64CheckOverflow> 1794 { 1795 public: Addition(const T & lhs,const U & rhs,T & result)1796 static SafeIntError Addition( const T& lhs, const U& rhs, T& result ) 1797 { 1798 // lhs unsigned __int64, rhs unsigned 1799 unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs; 1800 1801 // We added and it didn't get smaller 1802 if(tmp >= lhs) 1803 { 1804 result = (T)tmp; 1805 return SafeIntNoError; 1806 } 1807 1808 E::SafeIntOnOverflow(); 1809 return SafeIntArithmeticOverflow; 1810 } 1811 }; 1812 1813 template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastUint64CheckOverflowMax > 1814 { 1815 public: Addition(const T & lhs,const U & rhs,T & result)1816 static SafeIntError Addition( const T& lhs, const U& rhs, T& result ) 1817 { 1818 //lhs unsigned __int64, rhs unsigned 1819 unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs; 1820 1821 // We added and it didn't get smaller 1822 if( tmp >= lhs && tmp <= IntTraits< T >::maxInt ) 1823 { 1824 result = (T)tmp; 1825 return SafeIntNoError; 1826 } 1827 1828 E::SafeIntOnOverflow(); 1829 return SafeIntArithmeticOverflow; 1830 } 1831 }; 1832 1833 template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastIntCheckMinMax > 1834 { 1835 public: Addition(const T & lhs,const U & rhs,T & result)1836 static SafeIntError Addition( const T& lhs, const U& rhs, T& result ) 1837 { 1838 // 16-bit or less - one or both are signed 1839 __int32 tmp = lhs + rhs; 1840 1841 if( tmp <= (__int32)IntTraits< T >::maxInt && tmp >= (__int32)IntTraits< T >::minInt ) 1842 { 1843 result = (T)tmp; 1844 return SafeIntNoError; 1845 } 1846 1847 E::SafeIntOnOverflow(); 1848 return SafeIntArithmeticOverflow; 1849 } 1850 }; 1851 1852 #pragma warning(push) 1853 #pragma warning(disable:4702) 1854 template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastInt64CheckMinMax > 1855 { 1856 public: Addition(const T & lhs,const U & rhs,T & result)1857 static SafeIntError Addition( const T& lhs, const U& rhs, T& result ) 1858 { 1859 // 32-bit or less - one or both are signed 1860 __int64 tmp = (__int64)lhs + (__int64)rhs; 1861 1862 if( tmp <= (__int64)IntTraits< T >::maxInt && tmp >= (__int64)IntTraits< T >::minInt ) 1863 { 1864 result = (T)tmp; 1865 return SafeIntNoError; 1866 } 1867 1868 E::SafeIntOnOverflow(); 1869 return SafeIntArithmeticOverflow; 1870 // return E::SafeIntOnOverflow2(); 1871 } 1872 }; 1873 #pragma warning(pop) 1874 1875 template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastInt64CheckMax > 1876 { 1877 public: Addition(const T & lhs,const U & rhs,T & result)1878 static SafeIntError Addition( const T& lhs, const U& rhs, T& result ) 1879 { 1880 // 32-bit or less - lhs signed, rhs unsigned 1881 __int64 tmp = (__int64)lhs + (__int64)rhs; 1882 1883 if( tmp <= IntTraits< T >::maxInt ) 1884 { 1885 result = (T)tmp; 1886 return SafeIntNoError; 1887 } 1888 1889 E::SafeIntOnOverflow(); 1890 return SafeIntArithmeticOverflow; 1891 } 1892 }; 1893 1894 template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastUint64CheckMinMax > 1895 { 1896 public: Addition(const T & lhs,const U & rhs,T & result)1897 static SafeIntError Addition( const T& lhs, const U& rhs, T& result ) 1898 { 1899 // lhs is unsigned __int64, rhs signed 1900 unsigned __int64 tmp; 1901 1902 if( rhs < 0 ) 1903 { 1904 // So we're effectively subtracting 1905 tmp = AbsValueHelper< U >::Abs( rhs ); 1906 1907 if( tmp <= lhs ) 1908 { 1909 result = lhs - tmp; 1910 return SafeIntNoError; 1911 } 1912 } 1913 else 1914 { 1915 // now we know that rhs can be safely cast into an unsigned __int64 1916 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs; 1917 1918 // We added and it did not become smaller 1919 if( tmp >= lhs ) 1920 { 1921 result = (T)tmp; 1922 return SafeIntNoError; 1923 } 1924 } 1925 1926 E::SafeIntOnOverflow(); 1927 return SafeIntArithmeticOverflow; 1928 } 1929 }; 1930 1931 template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastUint64CheckMinMax2> 1932 { 1933 public: Addition(const T & lhs,const U & rhs,T & result)1934 static SafeIntError Addition( const T& lhs, const U& rhs, T& result ) 1935 { 1936 // lhs is unsigned and < 64-bit, rhs signed __int64 1937 if( rhs < 0 ) 1938 { 1939 if( lhs >= (unsigned __int64)( -rhs ) )//negation is safe, since rhs is 64-bit 1940 { 1941 result = (T)( lhs + rhs ); 1942 return SafeIntNoError; 1943 } 1944 } 1945 else 1946 { 1947 // now we know that rhs can be safely cast into an unsigned __int64 1948 unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs; 1949 1950 // special case - rhs cannot be larger than 0x7fffffffffffffff, lhs cannot be larger than 0xffffffff 1951 // it is not possible for the operation above to overflow, so just check max 1952 if( tmp <= IntTraits< T >::maxInt ) 1953 { 1954 result = (T)tmp; 1955 return SafeIntNoError; 1956 } 1957 } 1958 E::SafeIntOnOverflow(); 1959 return SafeIntArithmeticOverflow; 1960 } 1961 }; 1962 1963 template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastInt64CheckOverflow> 1964 { 1965 public: Addition(const T & lhs,const U & rhs,T & result)1966 static SafeIntError Addition( const T& lhs, const U& rhs, T& result ) 1967 { 1968 // lhs is signed __int64, rhs signed 1969 __int64 tmp = (__int64)lhs + (__int64)rhs; 1970 1971 if( lhs >= 0 ) 1972 { 1973 // mixed sign cannot overflow 1974 if( rhs >= 0 && tmp < lhs ) 1975 { 1976 E::SafeIntOnOverflow(); 1977 return SafeIntArithmeticOverflow; 1978 } 1979 } 1980 else 1981 { 1982 // lhs negative 1983 if( rhs < 0 && tmp > lhs ) 1984 { 1985 E::SafeIntOnOverflow(); 1986 return SafeIntArithmeticOverflow; 1987 } 1988 } 1989 1990 result = (T)tmp; 1991 return SafeIntNoError; 1992 } 1993 }; 1994 1995 template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastInt64CheckOverflowMinMax> 1996 { 1997 public: Addition(const T & lhs,const U & rhs,T & result)1998 static SafeIntError Addition( const T& lhs, const U& rhs, T& result ) 1999 { 2000 //rhs is signed __int64, lhs signed 2001 __int64 tmp; 2002 2003 if( AdditionHelper< __int64, __int64, E, AdditionState_CastInt64CheckOverflow >:: 2004 Addition( (__int64)lhs, (__int64)rhs, tmp ) == SafeIntNoError && 2005 tmp <= IntTraits< T >::maxInt && 2006 tmp >= IntTraits< T >::minInt ) 2007 { 2008 result = (T)tmp; 2009 return SafeIntNoError; 2010 } 2011 2012 E::SafeIntOnOverflow(); 2013 return SafeIntArithmeticOverflow; 2014 } 2015 }; 2016 2017 template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_CastInt64CheckOverflowMax > 2018 { 2019 public: Addition(const T & lhs,const U & rhs,T & result)2020 static SafeIntError Addition( const T& lhs, const U& rhs, T& result ) 2021 { 2022 //lhs is signed __int64, rhs unsigned < 64-bit 2023 __int64 tmp = lhs + (__int64)rhs; 2024 2025 if( tmp >= lhs ) 2026 { 2027 result = (T)tmp; 2028 return SafeIntNoError; 2029 } 2030 2031 E::SafeIntOnOverflow(); 2032 return SafeIntArithmeticOverflow; 2033 } 2034 }; 2035 2036 template < typename E > class AdditionHelper < __int64, unsigned __int64, E, AdditionState_ManualCheckInt64Uint64 > 2037 { 2038 public: Addition(const __int64 & lhs,const unsigned __int64 & rhs,__int64 & result)2039 static SafeIntError Addition( const __int64& lhs, const unsigned __int64& rhs, __int64& result ) 2040 { 2041 // rhs is unsigned __int64, lhs __int64 2042 __int64 tmp = lhs + (__int64)rhs; 2043 2044 if( tmp >= lhs ) 2045 { 2046 result = tmp; 2047 return SafeIntNoError; 2048 } 2049 2050 E::SafeIntOnOverflow(); 2051 return SafeIntArithmeticOverflow; 2052 } 2053 }; 2054 2055 template < typename T, typename U, typename E > class AdditionHelper < T, U, E, AdditionState_ManualCheck > 2056 { 2057 public: Addition(const T & lhs,const U & rhs,T & result)2058 static SafeIntError Addition( const T& lhs, const U& rhs, T& result ) 2059 { 2060 // rhs is unsigned __int64, lhs signed, 32-bit or less 2061 2062 if( (unsigned __int32)( rhs >> 32 ) == 0 ) 2063 { 2064 // Now it just happens to work out that the standard behavior does what we want 2065 // Adding explicit casts to show exactly what's happening here 2066 __int32 tmp = (__int32)( (unsigned __int32)rhs + (unsigned __int32)lhs ); 2067 2068 if( tmp >= lhs && 2069 SafeCastHelper< T, __int32, E >::Cast( tmp, result ) == SafeIntNoError ) 2070 return SafeIntNoError; 2071 } 2072 2073 E::SafeIntOnOverflow(); 2074 return SafeIntArithmeticOverflow; 2075 } 2076 }; 2077 2078 enum SubtractionState 2079 { 2080 SubtractionState_BothUnsigned, 2081 SubtractionState_CastIntCheckMinMax, 2082 SubtractionState_CastIntCheckMin, 2083 SubtractionState_CastInt64CheckMinMax, 2084 SubtractionState_CastInt64CheckMin, 2085 SubtractionState_Uint64Int, 2086 SubtractionState_UintInt64, 2087 SubtractionState_Int64Int, 2088 SubtractionState_IntInt64, 2089 SubtractionState_Int64Uint, 2090 SubtractionState_IntUint64, 2091 SubtractionState_Int64Uint64, 2092 // states for SubtractionMethod2 2093 SubtractionState_BothUnsigned2, 2094 SubtractionState_CastIntCheckMinMax2, 2095 SubtractionState_CastInt64CheckMinMax2, 2096 SubtractionState_Uint64Int2, 2097 SubtractionState_UintInt642, 2098 SubtractionState_Int64Int2, 2099 SubtractionState_IntInt642, 2100 SubtractionState_Int64Uint2, 2101 SubtractionState_IntUint642, 2102 SubtractionState_Int64Uint642, 2103 SubtractionState_Error 2104 }; 2105 2106 template < typename T, typename U > class SubtractionMethod 2107 { 2108 public: 2109 enum 2110 { 2111 // unsigned-unsigned 2112 method = ((IntRegion< T,U >::IntZone_UintLT32_UintLT32 || 2113 (IntRegion< T,U >::IntZone_Uint32_UintLT64) || 2114 (IntRegion< T,U >::IntZone_UintLT32_Uint32) || 2115 (IntRegion< T,U >::IntZone_Uint64_Uint) || 2116 (IntRegion< T,U >::IntZone_UintLT64_Uint64)) ? SubtractionState_BothUnsigned : 2117 // unsigned-signed 2118 (IntRegion< T,U >::IntZone_UintLT32_IntLT32) ? SubtractionState_CastIntCheckMinMax : 2119 (IntRegion< T,U >::IntZone_Uint32_IntLT64 || 2120 IntRegion< T,U >::IntZone_UintLT32_Int32) ? SubtractionState_CastInt64CheckMinMax : 2121 (IntRegion< T,U >::IntZone_Uint64_Int || 2122 IntRegion< T,U >::IntZone_Uint64_Int64) ? SubtractionState_Uint64Int : 2123 (IntRegion< T,U >::IntZone_UintLT64_Int64) ? SubtractionState_UintInt64 : 2124 // signed-signed 2125 (IntRegion< T,U >::IntZone_IntLT32_IntLT32) ? SubtractionState_CastIntCheckMinMax : 2126 (IntRegion< T,U >::IntZone_Int32_IntLT64 || 2127 IntRegion< T,U >::IntZone_IntLT32_Int32) ? SubtractionState_CastInt64CheckMinMax : 2128 (IntRegion< T,U >::IntZone_Int64_Int || 2129 IntRegion< T,U >::IntZone_Int64_Int64) ? SubtractionState_Int64Int : 2130 (IntRegion< T,U >::IntZone_IntLT64_Int64) ? SubtractionState_IntInt64 : 2131 // signed-unsigned 2132 (IntRegion< T,U >::IntZone_IntLT32_UintLT32) ? SubtractionState_CastIntCheckMin : 2133 (IntRegion< T,U >::IntZone_Int32_UintLT32 || 2134 IntRegion< T,U >::IntZone_IntLT64_Uint32) ? SubtractionState_CastInt64CheckMin : 2135 (IntRegion< T,U >::IntZone_Int64_UintLT64) ? SubtractionState_Int64Uint : 2136 (IntRegion< T,U >::IntZone_Int_Uint64) ? SubtractionState_IntUint64 : 2137 (IntRegion< T,U >::IntZone_Int64_Uint64) ? SubtractionState_Int64Uint64 : 2138 SubtractionState_Error) 2139 }; 2140 }; 2141 2142 // this is for the case of U - SafeInt< T, E > 2143 template < typename T, typename U > class SubtractionMethod2 2144 { 2145 public: 2146 enum 2147 { 2148 // unsigned-unsigned 2149 method = ((IntRegion< T,U >::IntZone_UintLT32_UintLT32 || 2150 (IntRegion< T,U >::IntZone_Uint32_UintLT64) || 2151 (IntRegion< T,U >::IntZone_UintLT32_Uint32) || 2152 (IntRegion< T,U >::IntZone_Uint64_Uint) || 2153 (IntRegion< T,U >::IntZone_UintLT64_Uint64)) ? SubtractionState_BothUnsigned2 : 2154 // unsigned-signed 2155 (IntRegion< T,U >::IntZone_UintLT32_IntLT32) ? SubtractionState_CastIntCheckMinMax2 : 2156 (IntRegion< T,U >::IntZone_Uint32_IntLT64 || 2157 IntRegion< T,U >::IntZone_UintLT32_Int32) ? SubtractionState_CastInt64CheckMinMax2 : 2158 (IntRegion< T,U >::IntZone_Uint64_Int || 2159 IntRegion< T,U >::IntZone_Uint64_Int64) ? SubtractionState_Uint64Int2 : 2160 (IntRegion< T,U >::IntZone_UintLT64_Int64) ? SubtractionState_UintInt642 : 2161 // signed-signed 2162 (IntRegion< T,U >::IntZone_IntLT32_IntLT32) ? SubtractionState_CastIntCheckMinMax2 : 2163 (IntRegion< T,U >::IntZone_Int32_IntLT64 || 2164 IntRegion< T,U >::IntZone_IntLT32_Int32) ? SubtractionState_CastInt64CheckMinMax2 : 2165 (IntRegion< T,U >::IntZone_Int64_Int || 2166 IntRegion< T,U >::IntZone_Int64_Int64) ? SubtractionState_Int64Int2 : 2167 (IntRegion< T,U >::IntZone_IntLT64_Int64) ? SubtractionState_IntInt642 : 2168 // signed-unsigned 2169 (IntRegion< T,U >::IntZone_IntLT32_UintLT32) ? SubtractionState_CastIntCheckMinMax2 : 2170 (IntRegion< T,U >::IntZone_Int32_UintLT32 || 2171 IntRegion< T,U >::IntZone_IntLT64_Uint32) ? SubtractionState_CastInt64CheckMinMax2 : 2172 (IntRegion< T,U >::IntZone_Int64_UintLT64) ? SubtractionState_Int64Uint2 : 2173 (IntRegion< T,U >::IntZone_Int_Uint64) ? SubtractionState_IntUint642 : 2174 (IntRegion< T,U >::IntZone_Int64_Uint64) ? SubtractionState_Int64Uint642 : 2175 SubtractionState_Error) 2176 }; 2177 }; 2178 2179 template < typename T, typename U, typename E, int Method = SubtractionMethod< T, U >::method > class SubtractionHelper; 2180 2181 template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_BothUnsigned > 2182 { 2183 public: Subtract(const T & lhs,const U & rhs,T & result)2184 static SafeIntError Subtract( const T& lhs, const U& rhs, T& result ) 2185 { 2186 // both are unsigned - easy case 2187 if( rhs <= lhs ) 2188 { 2189 result = (T)( lhs - rhs ); 2190 return SafeIntNoError; 2191 } 2192 2193 E::SafeIntOnOverflow(); 2194 return SafeIntArithmeticOverflow; 2195 } 2196 }; 2197 2198 template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_BothUnsigned2 > 2199 { 2200 public: Subtract(const T & lhs,const U & rhs,U & result)2201 static SafeIntError Subtract( const T& lhs, const U& rhs, U& result ) 2202 { 2203 // both are unsigned - easy case 2204 // Except we do have to check for overflow - lhs could be larger than result can hold 2205 if( rhs <= lhs ) 2206 { 2207 T tmp = (T)(lhs - rhs); 2208 return SafeCastHelper< U, T, E>::Cast( tmp, result); 2209 } 2210 2211 E::SafeIntOnOverflow(); 2212 return SafeIntArithmeticOverflow; 2213 } 2214 }; 2215 2216 template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_CastIntCheckMinMax > 2217 { 2218 public: Subtract(const T & lhs,const U & rhs,T & result)2219 static SafeIntError Subtract( const T& lhs, const U& rhs, T& result ) 2220 { 2221 // both values are 16-bit or less 2222 // rhs is signed, so could end up increasing or decreasing 2223 __int32 tmp = lhs - rhs; 2224 2225 if( SafeCastHelper< T, __int32, E >::Cast( tmp, result ) == SafeIntNoError ) 2226 { 2227 result = (T)tmp; 2228 return SafeIntNoError; 2229 } 2230 2231 E::SafeIntOnOverflow(); 2232 return SafeIntArithmeticOverflow; 2233 } 2234 }; 2235 2236 template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_CastIntCheckMinMax2 > 2237 { 2238 public: Subtract(const U & lhs,const T & rhs,T & result)2239 static SafeIntError Subtract( const U& lhs, const T& rhs, T& result ) 2240 { 2241 // both values are 16-bit or less 2242 // rhs is signed, so could end up increasing or decreasing 2243 __int32 tmp = lhs - rhs; 2244 2245 return SafeCastHelper< T, __int32, E >::Cast( tmp, result ); 2246 } 2247 }; 2248 2249 template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_CastIntCheckMin > 2250 { 2251 public: Subtract(const T & lhs,const U & rhs,T & result)2252 static SafeIntError Subtract( const T& lhs, const U& rhs, T& result ) 2253 { 2254 // both values are 16-bit or less 2255 // rhs is unsigned - check only minimum 2256 __int32 tmp = lhs - rhs; 2257 2258 if( tmp >= (__int32)IntTraits< T >::minInt ) 2259 { 2260 result = (T)tmp; 2261 return SafeIntNoError; 2262 } 2263 2264 E::SafeIntOnOverflow(); 2265 return SafeIntArithmeticOverflow; 2266 } 2267 }; 2268 2269 template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_CastInt64CheckMinMax > 2270 { 2271 public: Subtract(const T & lhs,const U & rhs,T & result)2272 static SafeIntError Subtract( const T& lhs, const U& rhs, T& result ) 2273 { 2274 // both values are 32-bit or less 2275 // rhs is signed, so could end up increasing or decreasing 2276 __int64 tmp = (__int64)lhs - (__int64)rhs; 2277 2278 return SafeCastHelper< T, __int64, E >::Cast( tmp, result ); 2279 } 2280 }; 2281 2282 template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_CastInt64CheckMinMax2 > 2283 { 2284 public: Subtract(const U & lhs,const T & rhs,T & result)2285 static SafeIntError Subtract( const U& lhs, const T& rhs, T& result ) 2286 { 2287 // both values are 32-bit or less 2288 // rhs is signed, so could end up increasing or decreasing 2289 __int64 tmp = (__int64)lhs - (__int64)rhs; 2290 2291 return SafeCastHelper< T, __int64, E >::Cast( tmp, result ); 2292 } 2293 }; 2294 2295 template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_CastInt64CheckMin > 2296 { 2297 public: Subtract(const T & lhs,const U & rhs,T & result)2298 static SafeIntError Subtract( const T& lhs, const U& rhs, T& result ) 2299 { 2300 // both values are 32-bit or less 2301 // rhs is unsigned - check only minimum 2302 __int64 tmp = (__int64)lhs - (__int64)rhs; 2303 2304 if( tmp >= (__int64)IntTraits< T >::minInt ) 2305 { 2306 result = (T)tmp; 2307 return SafeIntNoError; 2308 } 2309 2310 E::SafeIntOnOverflow(); 2311 return SafeIntArithmeticOverflow; 2312 } 2313 }; 2314 2315 template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_Uint64Int > 2316 { 2317 public: Subtract(const T & lhs,const U & rhs,T & result)2318 static SafeIntError Subtract( const T& lhs, const U& rhs, T& result ) 2319 { 2320 // lhs is an unsigned __int64, rhs signed 2321 // must first see if rhs is positive or negative 2322 if( rhs >= 0 ) 2323 { 2324 if( (unsigned __int64)rhs <= lhs ) 2325 { 2326 result = (T)( lhs - (unsigned __int64)rhs ); 2327 return SafeIntNoError; 2328 } 2329 } 2330 else 2331 { 2332 // we're now effectively adding 2333 T tmp = lhs + AbsValueHelper< U >::Abs( rhs ); 2334 2335 if(tmp >= lhs) 2336 { 2337 result = tmp; 2338 return SafeIntNoError; 2339 } 2340 } 2341 2342 E::SafeIntOnOverflow(); 2343 return SafeIntArithmeticOverflow; 2344 } 2345 }; 2346 2347 template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_Uint64Int2 > 2348 { 2349 public: Subtract(const U & lhs,const T & rhs,T & result)2350 static SafeIntError Subtract( const U& lhs, const T& rhs, T& result ) 2351 { 2352 // U is unsigned __int64, T is signed 2353 if( rhs < 0 ) 2354 { 2355 // treat this as addition 2356 unsigned __int64 tmp; 2357 2358 tmp = lhs + (unsigned __int64)AbsValueHelper< T >::Abs( rhs ); 2359 2360 // must check for addition overflow and max 2361 if( tmp >= lhs && tmp <= IntTraits< T >::maxInt ) 2362 { 2363 result = (T)tmp; 2364 return SafeIntNoError; 2365 } 2366 } 2367 else if( (unsigned __int64)rhs > lhs ) // now both are positive, so comparison always works 2368 { 2369 // result is negative 2370 // implies that lhs must fit into T, and result cannot overflow 2371 // Also allows us to drop to 32-bit math, which is faster on a 32-bit system 2372 result = (T)lhs - (T)rhs; 2373 return SafeIntNoError; 2374 } 2375 else 2376 { 2377 // result is positive 2378 unsigned __int64 tmp = (unsigned __int64)lhs - (unsigned __int64)rhs; 2379 2380 if( tmp <= IntTraits< T >::maxInt ) 2381 { 2382 result = (T)tmp; 2383 return SafeIntNoError; 2384 } 2385 } 2386 2387 E::SafeIntOnOverflow(); 2388 return SafeIntArithmeticOverflow; 2389 } 2390 }; 2391 2392 template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_UintInt64 > 2393 { 2394 public: Subtract(const T & lhs,const U & rhs,T & result)2395 static SafeIntError Subtract( const T& lhs, const U& rhs, T& result ) 2396 { 2397 // lhs is an unsigned int32 or smaller, rhs signed __int64 2398 // must first see if rhs is positive or negative 2399 if( rhs >= 0 ) 2400 { 2401 if( (unsigned __int64)rhs <= lhs ) 2402 { 2403 result = (T)( lhs - (T)rhs ); 2404 return SafeIntNoError; 2405 } 2406 } 2407 else 2408 { 2409 // we're now effectively adding 2410 // since lhs is 32-bit, and rhs cannot exceed 2^63 2411 // this addition cannot overflow 2412 unsigned __int64 tmp = lhs + (unsigned __int64)( -rhs ); // negation safe 2413 2414 // but we could exceed MaxInt 2415 if(tmp <= IntTraits< T >::maxInt) 2416 { 2417 result = (T)tmp; 2418 return SafeIntNoError; 2419 } 2420 } 2421 2422 E::SafeIntOnOverflow(); 2423 return SafeIntArithmeticOverflow; 2424 } 2425 }; 2426 2427 template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_UintInt642 > 2428 { 2429 public: Subtract(const U & lhs,const T & rhs,T & result)2430 static SafeIntError Subtract( const U& lhs, const T& rhs, T& result ) 2431 { 2432 // U unsigned 32-bit or less, T __int64 2433 if( rhs >= 0 ) 2434 { 2435 // overflow not possible 2436 result = (T)( (__int64)lhs - rhs ); 2437 return SafeIntNoError; 2438 } 2439 else 2440 { 2441 // we effectively have an addition 2442 // which cannot overflow internally 2443 unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)( -rhs ); 2444 2445 if( tmp <= (unsigned __int64)IntTraits< T >::maxInt ) 2446 { 2447 result = (T)tmp; 2448 return SafeIntNoError; 2449 } 2450 } 2451 2452 E::SafeIntOnOverflow(); 2453 return SafeIntArithmeticOverflow; 2454 } 2455 }; 2456 2457 template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_Int64Int > 2458 { 2459 public: Subtract(const T & lhs,const U & rhs,T & result)2460 static SafeIntError Subtract( const T& lhs, const U& rhs, T& result ) 2461 { 2462 // lhs is an __int64, rhs signed (up to 64-bit) 2463 // we have essentially 4 cases: 2464 // 2465 // 1) lhs positive, rhs positive - overflow not possible 2466 // 2) lhs positive, rhs negative - equivalent to addition - result >= lhs or error 2467 // 3) lhs negative, rhs positive - check result <= lhs 2468 // 4) lhs negative, rhs negative - overflow not possible 2469 2470 __int64 tmp = lhs - rhs; 2471 2472 // Note - ideally, we can order these so that true conditionals 2473 // lead to success, which enables better pipelining 2474 // It isn't practical here 2475 if( ( lhs >= 0 && rhs < 0 && tmp < lhs ) || // condition 2 2476 ( rhs >= 0 && tmp > lhs ) ) // condition 3 2477 { 2478 E::SafeIntOnOverflow(); 2479 return SafeIntArithmeticOverflow; 2480 } 2481 2482 result = (T)tmp; 2483 return SafeIntNoError; 2484 } 2485 }; 2486 2487 template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_Int64Int2 > 2488 { 2489 public: Subtract(const U & lhs,const T & rhs,T & result)2490 static SafeIntError Subtract( const U& lhs, const T& rhs, T& result ) 2491 { 2492 // lhs __int64, rhs any signed int (including __int64) 2493 __int64 tmp = lhs - rhs; 2494 2495 // we have essentially 4 cases: 2496 // 2497 // 1) lhs positive, rhs positive - overflow not possible in tmp 2498 // 2) lhs positive, rhs negative - equivalent to addition - result >= lhs or error 2499 // 3) lhs negative, rhs positive - check result <= lhs 2500 // 4) lhs negative, rhs negative - overflow not possible in tmp 2501 2502 if( lhs >= 0 ) 2503 { 2504 // if both positive, overflow to negative not possible 2505 // which is why we'll explicitly check maxInt, and not call SafeCast 2506 #pragma warning(suppress:4127) 2507 if( ( IntTraits< T >::isLT64Bit && tmp > IntTraits< T >::maxInt ) || 2508 ( rhs < 0 && tmp < lhs ) ) 2509 { 2510 E::SafeIntOnOverflow(); 2511 return SafeIntArithmeticOverflow; 2512 } 2513 } 2514 else 2515 { 2516 // lhs negative 2517 #pragma warning(suppress:4127) 2518 if( ( IntTraits< T >::isLT64Bit && tmp < IntTraits< T >::minInt) || 2519 ( rhs >=0 && tmp > lhs ) ) 2520 { 2521 E::SafeIntOnOverflow(); 2522 return SafeIntArithmeticOverflow; 2523 } 2524 } 2525 2526 result = (T)tmp; 2527 return SafeIntNoError; 2528 } 2529 }; 2530 2531 template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_IntInt64 > 2532 { 2533 public: Subtract(const T & lhs,const U & rhs,T & result)2534 static SafeIntError Subtract( const T& lhs, const U& rhs, T& result ) 2535 { 2536 // lhs is a 32-bit int or less, rhs __int64 2537 // we have essentially 4 cases: 2538 // 2539 // lhs positive, rhs positive - rhs could be larger than lhs can represent 2540 // lhs positive, rhs negative - additive case - check tmp >= lhs and tmp > max int 2541 // lhs negative, rhs positive - check tmp <= lhs and tmp < min int 2542 // lhs negative, rhs negative - addition cannot internally overflow, check against max 2543 2544 __int64 tmp = (__int64)lhs - rhs; 2545 2546 if( lhs >= 0 ) 2547 { 2548 // first case 2549 if( rhs >= 0 ) 2550 { 2551 if( tmp >= IntTraits< T >::minInt ) 2552 { 2553 result = (T)tmp; 2554 return SafeIntNoError; 2555 } 2556 } 2557 else 2558 { 2559 // second case 2560 if( tmp >= lhs && tmp <= IntTraits< T >::maxInt ) 2561 { 2562 result = (T)tmp; 2563 return SafeIntNoError; 2564 } 2565 } 2566 } 2567 else 2568 { 2569 // lhs < 0 2570 // third case 2571 if( rhs >= 0 ) 2572 { 2573 if( tmp <= lhs && tmp >= IntTraits< T >::minInt ) 2574 { 2575 result = (T)tmp; 2576 return SafeIntNoError; 2577 } 2578 } 2579 else 2580 { 2581 // fourth case 2582 if( tmp <= IntTraits< T >::maxInt ) 2583 { 2584 result = (T)tmp; 2585 return SafeIntNoError; 2586 } 2587 } 2588 } 2589 2590 E::SafeIntOnOverflow(); 2591 return SafeIntArithmeticOverflow; 2592 } 2593 }; 2594 2595 template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_IntInt642 > 2596 { 2597 public: Subtract(const U & lhs,const T & rhs,T & result)2598 static SafeIntError Subtract( const U& lhs, const T& rhs, T& result ) 2599 { 2600 // lhs is any signed int32 or smaller, rhs is int64 2601 __int64 tmp = (__int64)lhs - rhs; 2602 2603 if( ( lhs >= 0 && rhs < 0 && tmp < lhs ) || 2604 ( rhs > 0 && tmp > lhs ) ) 2605 { 2606 E::SafeIntOnOverflow(); 2607 return SafeIntArithmeticOverflow; 2608 //else OK 2609 } 2610 2611 result = (T)tmp; 2612 return SafeIntNoError; 2613 } 2614 }; 2615 2616 template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_Int64Uint > 2617 { 2618 public: Subtract(const T & lhs,const U & rhs,T & result)2619 static SafeIntError Subtract( const T& lhs, const U& rhs, T& result ) 2620 { 2621 // lhs is a 64-bit int, rhs unsigned int32 or smaller 2622 2623 __int64 tmp = lhs - (__int64)rhs; 2624 2625 if( tmp <= lhs ) 2626 { 2627 result = (T)tmp; 2628 return SafeIntNoError; 2629 } 2630 2631 E::SafeIntOnOverflow(); 2632 return SafeIntArithmeticOverflow; 2633 } 2634 }; 2635 2636 template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_Int64Uint2 > 2637 { 2638 public: 2639 // lhs is __int64, rhs is unsigned 32-bit or smaller Subtract(const U & lhs,const T & rhs,T & result)2640 static SafeIntError Subtract( const U& lhs, const T& rhs, T& result ) 2641 { 2642 __int64 tmp = lhs - (__int64)rhs; 2643 2644 if( tmp <= IntTraits< T >::maxInt && tmp >= IntTraits< T >::minInt ) 2645 { 2646 result = (T)tmp; 2647 return SafeIntNoError; 2648 } 2649 2650 E::SafeIntOnOverflow(); 2651 return SafeIntArithmeticOverflow; 2652 } 2653 }; 2654 2655 template < typename T, typename U, typename E > class SubtractionHelper< T, U, E, SubtractionState_IntUint64 > 2656 { 2657 public: Subtract(const T & lhs,const U & rhs,T & result)2658 static SafeIntError Subtract( const T& lhs, const U& rhs, T& result ) 2659 { 2660 // lhs is any signed int, rhs unsigned int64 2661 // check against available range 2662 2663 // We need the absolute value of IntTraits< T >::minInt 2664 // This will give it to us without extraneous compiler warnings 2665 const unsigned __int64 AbsMinIntT = (unsigned __int64)IntTraits< T >::maxInt + 1; 2666 2667 if( lhs < 0 ) 2668 { 2669 if( rhs <= AbsMinIntT - AbsValueHelper< T >::Abs( lhs ) ) 2670 { 2671 result = (T)( lhs - rhs ); 2672 return SafeIntNoError; 2673 } 2674 } 2675 else 2676 { 2677 if( rhs <= AbsMinIntT + (unsigned __int64)lhs ) 2678 { 2679 result = (T)( lhs - rhs ); 2680 return SafeIntNoError; 2681 } 2682 } 2683 2684 E::SafeIntOnOverflow(); 2685 return SafeIntArithmeticOverflow; 2686 } 2687 }; 2688 2689 template < typename U, typename T, typename E > class SubtractionHelper< U, T, E, SubtractionState_IntUint642 > 2690 { 2691 public: Subtract(const U & lhs,const T & rhs,T & result)2692 static SafeIntError Subtract( const U& lhs, const T& rhs, T& result ) 2693 { 2694 // We run into upcasting problems on comparison - needs 2 checks 2695 if( lhs >= 0 && (T)lhs >= rhs ) 2696 { 2697 result = (T)((U)lhs - (U)rhs); 2698 return SafeIntNoError; 2699 } 2700 2701 E::SafeIntOnOverflow(); 2702 return SafeIntArithmeticOverflow; 2703 } 2704 }; 2705 2706 template < typename E > class SubtractionHelper< __int64, unsigned __int64, E, SubtractionState_Int64Uint64 > 2707 { 2708 public: Subtract(const __int64 & lhs,const unsigned __int64 & rhs,__int64 & result)2709 static SafeIntError Subtract( const __int64& lhs, const unsigned __int64& rhs, __int64& result ) 2710 { 2711 // if we subtract, and it gets larger, there's a problem 2712 __int64 tmp = lhs - (__int64)rhs; 2713 2714 if( tmp <= lhs ) 2715 { 2716 result = tmp; 2717 return SafeIntNoError; 2718 } 2719 E::SafeIntOnOverflow(); 2720 return SafeIntArithmeticOverflow; 2721 } 2722 }; 2723 2724 template < typename E > class SubtractionHelper< __int64, unsigned __int64, E, SubtractionState_Int64Uint642 > 2725 { 2726 public: 2727 // If lhs is negative, immediate problem - return must be positive, and subtracting only makes it 2728 // get smaller. If rhs > lhs, then it would also go negative, which is the other case Subtract(const __int64 & lhs,const unsigned __int64 & rhs,unsigned __int64 & result)2729 static SafeIntError Subtract( const __int64& lhs, const unsigned __int64& rhs, unsigned __int64& result ) 2730 { 2731 if( lhs >= 0 && (unsigned __int64)lhs >= rhs ) 2732 { 2733 result = (unsigned __int64)lhs - rhs; 2734 return SafeIntNoError; 2735 } 2736 2737 E::SafeIntOnOverflow(); 2738 return SafeIntArithmeticOverflow; 2739 } 2740 }; 2741 2742 enum BinaryState 2743 { 2744 BinaryState_OK, 2745 BinaryState_Int8, 2746 BinaryState_Int16, 2747 BinaryState_Int32 2748 }; 2749 2750 template < typename T, typename U > class BinaryMethod 2751 { 2752 public: 2753 enum 2754 { 2755 // If both operands are unsigned OR 2756 // return type is smaller than rhs OR 2757 // return type is larger and rhs is unsigned 2758 // Then binary operations won't produce unexpected results 2759 method = ( sizeof( T ) <= sizeof( U ) || 2760 SafeIntCompare< T, U >::isBothUnsigned || 2761 !IntTraits< U >::isSigned ) ? BinaryState_OK : 2762 IntTraits< U >::isInt8 ? BinaryState_Int8 : 2763 IntTraits< U >::isInt16 ? BinaryState_Int16 2764 : BinaryState_Int32 2765 }; 2766 }; 2767 2768 template < typename T, typename U, int Method = BinaryMethod< T, U >::method > class BinaryAndHelper; 2769 2770 template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_OK > 2771 { 2772 public: And(T lhs,U rhs)2773 static T And( T lhs, U rhs ){ return (T)( lhs & rhs ); } 2774 }; 2775 2776 template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_Int8 > 2777 { 2778 public: And(T lhs,U rhs)2779 static T And( T lhs, U rhs ) 2780 { 2781 // cast forces sign extension to be zeros 2782 _SAFEINT_BINARY_ASSERT( ( lhs & rhs ) == ( lhs & (unsigned __int8)rhs ) ); 2783 return (T)( lhs & (unsigned __int8)rhs ); 2784 } 2785 }; 2786 2787 template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_Int16 > 2788 { 2789 public: And(T lhs,U rhs)2790 static T And( T lhs, U rhs ) 2791 { 2792 //cast forces sign extension to be zeros 2793 _SAFEINT_BINARY_ASSERT( ( lhs & rhs ) == ( lhs & (unsigned __int16)rhs ) ); 2794 return (T)( lhs & (unsigned __int16)rhs ); 2795 } 2796 }; 2797 2798 template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_Int32 > 2799 { 2800 public: And(T lhs,U rhs)2801 static T And( T lhs, U rhs ) 2802 { 2803 //cast forces sign extension to be zeros 2804 _SAFEINT_BINARY_ASSERT( ( lhs & rhs ) == ( lhs & (unsigned __int32)rhs ) ); 2805 return (T)( lhs & (unsigned __int32)rhs ); 2806 } 2807 }; 2808 2809 template < typename T, typename U, int Method = BinaryMethod< T, U >::method > class BinaryOrHelper; 2810 2811 template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_OK > 2812 { 2813 public: Or(T lhs,U rhs)2814 static T Or( T lhs, U rhs ){ return (T)( lhs | rhs ); } 2815 }; 2816 2817 template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_Int8 > 2818 { 2819 public: Or(T lhs,U rhs)2820 static T Or( T lhs, U rhs ) 2821 { 2822 //cast forces sign extension to be zeros 2823 _SAFEINT_BINARY_ASSERT( ( lhs | rhs ) == ( lhs | (unsigned __int8)rhs ) ); 2824 return (T)( lhs | (unsigned __int8)rhs ); 2825 } 2826 }; 2827 2828 template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_Int16 > 2829 { 2830 public: Or(T lhs,U rhs)2831 static T Or( T lhs, U rhs ) 2832 { 2833 //cast forces sign extension to be zeros 2834 _SAFEINT_BINARY_ASSERT( ( lhs | rhs ) == ( lhs | (unsigned __int16)rhs ) ); 2835 return (T)( lhs | (unsigned __int16)rhs ); 2836 } 2837 }; 2838 2839 template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_Int32 > 2840 { 2841 public: Or(T lhs,U rhs)2842 static T Or( T lhs, U rhs ) 2843 { 2844 //cast forces sign extension to be zeros 2845 _SAFEINT_BINARY_ASSERT( ( lhs | rhs ) == ( lhs | (unsigned __int32)rhs ) ); 2846 return (T)( lhs | (unsigned __int32)rhs ); 2847 } 2848 }; 2849 2850 template <typename T, typename U, int Method = BinaryMethod< T, U >::method > class BinaryXorHelper; 2851 2852 template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_OK > 2853 { 2854 public: Xor(T lhs,U rhs)2855 static T Xor( T lhs, U rhs ){ return (T)( lhs ^ rhs ); } 2856 }; 2857 2858 template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_Int8 > 2859 { 2860 public: Xor(T lhs,U rhs)2861 static T Xor( T lhs, U rhs ) 2862 { 2863 // cast forces sign extension to be zeros 2864 _SAFEINT_BINARY_ASSERT( ( lhs ^ rhs ) == ( lhs ^ (unsigned __int8)rhs ) ); 2865 return (T)( lhs ^ (unsigned __int8)rhs ); 2866 } 2867 }; 2868 2869 template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_Int16 > 2870 { 2871 public: Xor(T lhs,U rhs)2872 static T Xor( T lhs, U rhs ) 2873 { 2874 // cast forces sign extension to be zeros 2875 _SAFEINT_BINARY_ASSERT( ( lhs ^ rhs ) == ( lhs ^ (unsigned __int16)rhs ) ); 2876 return (T)( lhs ^ (unsigned __int16)rhs ); 2877 } 2878 }; 2879 2880 template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_Int32 > 2881 { 2882 public: Xor(T lhs,U rhs)2883 static T Xor( T lhs, U rhs ) 2884 { 2885 // cast forces sign extension to be zeros 2886 _SAFEINT_BINARY_ASSERT( ( lhs ^ rhs ) == ( lhs ^ (unsigned __int32)rhs ) ); 2887 return (T)( lhs ^ (unsigned __int32)rhs ); 2888 } 2889 }; 2890 2891 #pragma warning(pop) 2892 } // namespace details 2893 2894 } // namespace utilities 2895 2896 } // namespace msl 2897 2898 #pragma pack(pop) 2899