diff --git a/src/CLR/CorLib/corlib_native_System_Convert.cpp b/src/CLR/CorLib/corlib_native_System_Convert.cpp index 8b6d693e47..a925e9e96b 100644 --- a/src/CLR/CorLib/corlib_native_System_Convert.cpp +++ b/src/CLR/CorLib/corlib_native_System_Convert.cpp @@ -25,9 +25,29 @@ HRESULT Library_corlib_native_System_Convert::NativeToInt64___STATIC__I8__STRING long long minValue = stack.Arg2().NumericByRef().s8; long long maxValue = stack.Arg3().NumericByRef().s8; + // normally we check if the result is in the given range + bool check = true; + + // Int64? => use also strtoull the result will be casted to Int64 + if (isSigned && maxValue == 0x7FFFFFFFFFFFFFFF) isSigned = false; + + // UInt64? => use also strtoull the result will be casted to Int64 and bypass the range check + if (minValue == 0 && maxValue == 0) + { + isSigned = false; + check = false; + } + + // convert via strtoll / strtoull result = isSigned ? strtoll(str, nullptr, radix) : (long long) strtoull(str, nullptr, radix); - stack.SetResult_I8 ((result > maxValue || result < minValue) ? zero : result); + // the signed values for SByte, Int16 and Int32 are always positive for base 2, 8 or 16 conversions + // because the 64-bit function strtoll is used; need the post process the value + // if the result is greater max and smaller (max + 1) * 2 this value should be subtracted + if (isSigned && result > maxValue && result < (maxValue + 1) * 2) result -= (maxValue + 1) * 2; + + // for UInt64 the check will be bypassed + stack.SetResult_I8 ((check && (result > maxValue || result < minValue)) ? zero : result); #else // support for conversion from base 10 and 16 (partial)