/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/VisualBasic/Portable/Semantics/CompileTimeCalculations.vb
774 строки
31 KB
Michael Liu
Fix Double-to-Long overflow check (#73016)
09 май 2024, 19:48
Не верифицирован
09 май 2024, 19:48
8cd5d5e
Код
Авторство
О чём код?
' Licensed to the .NET Foundation under one or more agreements. ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. Option Strict On Option Explicit On Option Infer On Imports System.Runtime.CompilerServices Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic Friend Module CompileTimeCalculations Friend Function UncheckedCLng(v As ULong) As Long Return CType(v, Long) End Function Friend Function UncheckedCLng(v As Double) As Long Return CType(v, Long) End Function Friend Function UncheckedCULng(v As Long) As ULong Return CType(v, ULong) End Function Friend Function UncheckedCULng(v As Integer) As ULong Return CType(v, ULong) End Function Friend Function UncheckedCULng(v As Double) As ULong Return CType(v, ULong) End Function Friend Function UncheckedCInt(v As ULong) As Integer Return CType(v, Integer) End Function Friend Function UncheckedCInt(v As Long) As Integer Return CType(v, Integer) End Function Friend Function UncheckedCUInt(v As ULong) As UInteger Return CType(v, UInteger) End Function Friend Function UncheckedCUInt(v As Long) As UInteger Return CType(v, UInteger) End Function Friend Function UncheckedCUInt(v As Integer) As UInteger Return CType(v, UInteger) End Function Friend Function UncheckedCShort(v As ULong) As Short Return CType(v, Short) End Function Friend Function UncheckedCShort(v As Long) As Short Return CType(v, Short) End Function Friend Function UncheckedCShort(v As Integer) As Short Return CType(v, Short) End Function Friend Function UncheckedCShort(v As UShort) As Short Return CType(v, Short) End Function Friend Function UncheckedCInt(v As UInteger) As Integer Return CType(v, Integer) End Function Friend Function UncheckedCShort(v As UInteger) As Short Return CType(v, Short) End Function Friend Function UncheckedCUShort(v As Short) As UShort Return CType(v, UShort) End Function Friend Function UncheckedCUShort(v As Integer) As UShort Return CType(v, UShort) End Function Friend Function UncheckedCUShort(v As Long) As UShort Return CType(v, UShort) End Function Friend Function UncheckedCByte(v As SByte) As Byte Return CType(v, Byte) End Function Friend Function UncheckedCByte(v As Integer) As Byte Return CType(v, Byte) End Function Friend Function UncheckedCByte(v As Long) As Byte Return CType(v, Byte) End Function Friend Function UncheckedCByte(v As UShort) As Byte Return CType(v, Byte) End Function Friend Function UncheckedCSByte(v As Byte) As SByte Return CType(v, SByte) End Function Friend Function UncheckedCSByte(v As Integer) As SByte Return CType(v, SByte) End Function Friend Function UncheckedCSByte(v As Long) As SByte Return CType(v, SByte) End Function Friend Function UncheckedMul(x As Integer, y As Integer) As Integer Return x * y End Function Friend Function UncheckedMul(x As Long, y As Long) As Long Return x * y End Function Friend Function UncheckedIntegralDiv(x As Long, y As Long) As Long If y = -1 Then Return UncheckedNegate(x) End If Return x \ y End Function Private Function UncheckedAdd(x As Long, y As Long) As Long Return x + y End Function Private Function UncheckedNegate(x As Long) As Long Return -x End Function Friend Function GetConstantValueAsInt64(ByRef value As ConstantValue) As Long Select Case (value.Discriminator) Case ConstantValueTypeDiscriminator.SByte : Return value.SByteValue Case ConstantValueTypeDiscriminator.Byte : Return value.ByteValue Case ConstantValueTypeDiscriminator.Int16 : Return value.Int16Value Case ConstantValueTypeDiscriminator.UInt16 : Return value.UInt16Value Case ConstantValueTypeDiscriminator.Int32 : Return value.Int32Value Case ConstantValueTypeDiscriminator.UInt32 : Return value.UInt32Value Case ConstantValueTypeDiscriminator.Int64 : Return value.Int64Value Case ConstantValueTypeDiscriminator.UInt64 : Return UncheckedCLng(value.UInt64Value) Case ConstantValueTypeDiscriminator.Char : Return AscW(value.CharValue) Case ConstantValueTypeDiscriminator.Boolean : Return If(value.BooleanValue, 1, 0) Case ConstantValueTypeDiscriminator.DateTime : Return value.DateTimeValue.Ticks Case Else : Throw ExceptionUtilities.UnexpectedValue(value.Discriminator) End Select End Function Friend Function GetConstantValue(type As ConstantValueTypeDiscriminator, value As Long) As ConstantValue Dim result As ConstantValue Select Case (type) Case ConstantValueTypeDiscriminator.SByte : result = ConstantValue.Create(UncheckedCSByte(value)) Case ConstantValueTypeDiscriminator.Byte : result = ConstantValue.Create(UncheckedCByte(value)) Case ConstantValueTypeDiscriminator.Int16 : result = ConstantValue.Create(UncheckedCShort(value)) Case ConstantValueTypeDiscriminator.UInt16 : result = ConstantValue.Create(UncheckedCUShort(value)) Case ConstantValueTypeDiscriminator.Int32 : result = ConstantValue.Create(UncheckedCInt(value)) Case ConstantValueTypeDiscriminator.UInt32 : result = ConstantValue.Create(UncheckedCUInt(value)) Case ConstantValueTypeDiscriminator.Int64 : result = ConstantValue.Create(value) Case ConstantValueTypeDiscriminator.UInt64 : result = ConstantValue.Create(UncheckedCULng(value)) Case ConstantValueTypeDiscriminator.Char : result = ConstantValue.Create(ChrW(UncheckedCInt(value))) Case ConstantValueTypeDiscriminator.Boolean : result = ConstantValue.Create(If(value = 0, False, True)) Case ConstantValueTypeDiscriminator.DateTime : result = ConstantValue.Create(New DateTime(value)) Case Else : Throw ExceptionUtilities.UnexpectedValue(type) End Select Debug.Assert(result.Discriminator = type) Return result End Function Friend Function NarrowIntegralResult( sourceValue As Long, sourceType As ConstantValueTypeDiscriminator, resultType As ConstantValueTypeDiscriminator, ByRef overflow As Boolean ) As Long Dim resultValue As Long = 0 Select Case (resultType) Case ConstantValueTypeDiscriminator.Boolean resultValue = If(sourceValue = 0, 0, 1) Return resultValue Case ConstantValueTypeDiscriminator.SByte resultValue = UncheckedCSByte(sourceValue) Case ConstantValueTypeDiscriminator.Byte resultValue = UncheckedCByte(sourceValue) Case ConstantValueTypeDiscriminator.Int16 resultValue = UncheckedCShort(sourceValue) Case ConstantValueTypeDiscriminator.UInt16 resultValue = UncheckedCUShort(sourceValue) Case ConstantValueTypeDiscriminator.Int32 resultValue = UncheckedCInt(sourceValue) Case ConstantValueTypeDiscriminator.UInt32 resultValue = UncheckedCUInt(sourceValue) Case ConstantValueTypeDiscriminator.Int64 resultValue = sourceValue Case ConstantValueTypeDiscriminator.UInt64 resultValue = sourceValue 'UncheckedCLng(UncheckedCULng(SourceValue)) Case ConstantValueTypeDiscriminator.Char resultValue = UncheckedCUShort(sourceValue) ' // ?? overflow? Case Else Throw ExceptionUtilities.UnexpectedValue(resultType) End Select If Not ConstantValue.IsBooleanType(sourceType) AndAlso (ConstantValue.IsUnsignedIntegralType(sourceType) Xor ConstantValue.IsUnsignedIntegralType(resultType)) Then ' // If source is a signed type and is a negative value or ' // target is a signed type and results in a negative ' // value, indicate overflow. If Not ConstantValue.IsUnsignedIntegralType(sourceType) Then If sourceValue < 0 Then overflow = True End If Else Debug.Assert(Not ConstantValue.IsUnsignedIntegralType(resultType), "Expected signed Target type!!!") If resultValue < 0 Then overflow = True End If End If End If If resultValue <> sourceValue Then overflow = True End If Return resultValue End Function Friend Function NarrowIntegralResult( sourceValue As Long, sourceType As SpecialType, resultType As SpecialType, ByRef overflow As Boolean ) As Long Return NarrowIntegralResult(sourceValue, sourceType.ToConstantValueDiscriminator(), resultType.ToConstantValueDiscriminator(), overflow) End Function ''' <summary> ''' Narrow a quadword result to a specific integral type, setting Overflow true ''' if the result value cannot be represented in the result type. ''' </summary> Friend Function NarrowIntegralResult( sourceValue As Long, sourceType As TypeSymbol, resultType As TypeSymbol, ByRef overflow As Boolean) As Long Debug.Assert(sourceType.IsIntegralType() OrElse sourceType.IsBooleanType() OrElse sourceType.IsCharType(), "Unexpected source type passed in to conversion function!!!") Return NarrowIntegralResult(sourceValue, sourceType.GetConstantValueTypeDiscriminator(), resultType.GetConstantValueTypeDiscriminator(), overflow) End Function Friend Function ConvertIntegralValue( sourceValue As Long, sourceType As ConstantValueTypeDiscriminator, targetType As ConstantValueTypeDiscriminator, ByRef integerOverflow As Boolean ) As ConstantValue Debug.Assert(ConstantValue.IsIntegralType(sourceType) OrElse ConstantValue.IsBooleanType(sourceType) OrElse ConstantValue.IsCharType(sourceType), "Unexpected source type passed in to conversion function!!!") If ConstantValue.IsIntegralType(targetType) OrElse ConstantValue.IsBooleanType(targetType) OrElse ConstantValue.IsCharType(targetType) Then Return GetConstantValue(targetType, NarrowIntegralResult(sourceValue, sourceType, targetType, integerOverflow)) End If If ConstantValue.IsStringType(targetType) Then 'This is correct only if the input type is Char. If ConstantValue.IsCharType(sourceType) Then Return ConstantValue.Create(New String(ChrW(UncheckedCInt(sourceValue)), 1)) End If End If If ConstantValue.IsFloatingType(targetType) Then Return ConvertFloatingValue( If(ConstantValue.IsUnsignedIntegralType(sourceType), CType(UncheckedCULng(sourceValue), Double), CType(sourceValue, Double)), targetType, integerOverflow) End If If ConstantValue.IsDecimalType(targetType) Then Dim resultValue As Decimal Dim sign As Boolean If Not ConstantValue.IsUnsignedIntegralType(sourceType) AndAlso sourceValue < 0 Then ' // Negative numbers need converted to positive and set the negative sign bit sign = True sourceValue = -sourceValue Else sign = False End If Dim lo32 As Integer = UncheckedCInt(sourceValue And &HFFFFFFFF) ' // We include the sign bit here because we negated a negative above, so the ' // only number that still has the sign bit set is the maximum negative number ' // (which has no positive counterpart) Dim mid32 As Integer = UncheckedCInt((sourceValue And &HFFFFFFFF00000000) >> 32) Dim hi32 As Integer = 0 Dim scale As Byte = 0 resultValue = New Decimal(lo32, mid32, hi32, sign, scale) Return ConvertDecimalValue(resultValue, targetType, integerOverflow) End If Throw ExceptionUtilities.Unreachable() End Function Friend Function ConvertFloatingValue( sourceValue As Double, targetType As ConstantValueTypeDiscriminator, ByRef integerOverflow As Boolean ) As ConstantValue Dim overflow As Boolean = False If (ConstantValue.IsBooleanType(targetType)) Then Return ConvertIntegralValue(If(sourceValue = 0.0, 0, 1), ConstantValueTypeDiscriminator.Int64, targetType, integerOverflow) End If If ConstantValue.IsIntegralType(targetType) OrElse ConstantValue.IsCharType(targetType) Then overflow = DetectFloatingToIntegralOverflow(sourceValue, ConstantValue.IsUnsignedIntegralType(targetType)) If Not overflow Then Dim integralValue As Long Dim temporary As Double Dim floor As Double Dim sourceIntegralType As ConstantValueTypeDiscriminator ' // VB has different rounding behavior than C by default. Ensure we ' // are using the right type of rounding temporary = sourceValue + 0.5 ' // We had a number that was equally close to 2 integers. ' // We need to return the even one. floor = Math.Floor(temporary) '[AlekseyT]: Using Math.IEEERemainder as a replacement for fmod. If floor <> temporary OrElse Math.IEEERemainder(temporary, 2.0) = 0 Then integralValue = If(IsUnsignedLongType(targetType), ConvertFloatingToUI64(floor), UncheckedCLng(floor)) Else integralValue = If(IsUnsignedLongType(targetType), ConvertFloatingToUI64(floor - 1.0), UncheckedCLng(floor - 1.0)) End If If sourceValue < 0 Then sourceIntegralType = ConstantValueTypeDiscriminator.Int64 Else sourceIntegralType = ConstantValueTypeDiscriminator.UInt64 End If Return ConvertIntegralValue(integralValue, sourceIntegralType, targetType, integerOverflow) End If End If If ConstantValue.IsFloatingType(targetType) Then Dim resultValue As Double = NarrowFloatingResult(sourceValue, targetType, overflow) ' // We have decided to ignore overflows in compile-time evaluation ' // of floating expressions. If targetType = ConstantValueTypeDiscriminator.Single Then Return ConstantValue.Create(CType(resultValue, Single)) End If Debug.Assert(targetType = ConstantValueTypeDiscriminator.Double) Return ConstantValue.Create(resultValue) End If If ConstantValue.IsDecimalType(targetType) Then Dim resultValue As Decimal Try resultValue = Convert.ToDecimal(sourceValue) Catch ex As OverflowException overflow = True End Try If Not overflow Then Return ConvertDecimalValue(resultValue, targetType, integerOverflow) End If End If If overflow Then Return ConstantValue.Bad End If Throw ExceptionUtilities.Unreachable() End Function Friend Function ConvertDecimalValue( sourceValue As Decimal, targetType As ConstantValueTypeDiscriminator, ByRef integerOverflow As Boolean ) As ConstantValue Dim overflow As Boolean = False If ConstantValue.IsIntegralType(targetType) OrElse ConstantValue.IsCharType(targetType) Then Dim isNegative As Boolean Dim scale As Byte Dim low, mid, high As UInteger sourceValue.GetBits(isNegative, scale, low, mid, high) If scale = 0 Then Dim resultValue As Long ' Easy case: no scale factor. overflow = high <> 0 If Not overflow Then resultValue = (CLng(mid) << 32) Or low Dim sourceIntegralType As ConstantValueTypeDiscriminator = Nothing If isNegative Then ' The source value is negative, so we need to negate the result value. ' If the result type is unsigned, or the result value is already ' large enough that it consumes the sign bit, then we have overflowed. If ConstantValue.IsUnsignedIntegralType(targetType) OrElse UncheckedCULng(resultValue) > &H8000000000000000UL Then overflow = True Else resultValue = UncheckedNegate(resultValue) sourceIntegralType = ConstantValueTypeDiscriminator.Int64 End If Else sourceIntegralType = ConstantValueTypeDiscriminator.UInt64 End If If Not overflow Then Return ConvertIntegralValue(resultValue, sourceIntegralType, targetType, integerOverflow) End If End If Else Dim resultValue As Double ' // No overflow possible resultValue = Decimal.ToDouble(sourceValue) Return ConvertFloatingValue(resultValue, targetType, integerOverflow) End If End If If ConstantValue.IsFloatingType(targetType) OrElse ConstantValue.IsBooleanType(targetType) Then Dim resultValue As Double ' // No overflow possible resultValue = Decimal.ToDouble(sourceValue) Return ConvertFloatingValue(resultValue, targetType, integerOverflow) End If If ConstantValue.IsDecimalType(targetType) Then Return ConstantValue.Create(sourceValue) End If If overflow Then Return ConstantValue.Bad End If Throw ExceptionUtilities.Unreachable() End Function Friend Function NarrowFloatingResult( value As Double, resultType As ConstantValueTypeDiscriminator, ByRef overflow As Boolean ) As Double If Double.IsNaN(value) Then overflow = True End If Select Case (resultType) Case ConstantValueTypeDiscriminator.Double Return value Case ConstantValueTypeDiscriminator.Single If value > Single.MaxValue OrElse value < Single.MinValue Then overflow = True End If Return CType(value, Single) Case Else Throw ExceptionUtilities.UnexpectedValue(resultType) End Select Return value End Function Friend Function NarrowFloatingResult( value As Double, resultType As SpecialType, ByRef overflow As Boolean ) As Double If Double.IsNaN(value) Then overflow = True End If Select Case resultType Case SpecialType.System_Double Return value Case SpecialType.System_Single If value > Single.MaxValue OrElse value < Single.MinValue Then overflow = True End If Return CType(value, Single) Case Else Throw ExceptionUtilities.UnexpectedValue(resultType) End Select Return value End Function Private Function DetectFloatingToIntegralOverflow( sourceValue As Double, isUnsigned As Boolean ) As Boolean If isUnsigned Then ' // this code is shared by fjitdef.h If sourceValue < &HF000000000000000UL Then If sourceValue > -1 Then Return False End If Else Dim temporary As Double = (sourceValue - &HF000000000000000UL) If temporary < &H7000000000000000L AndAlso UncheckedCLng(temporary) < &H1000000000000000L Then Return False End If End If Else ' // this code is shared by fjitdef.h If sourceValue < -&H7000000000000000L Then Dim temporary As Double = sourceValue - (-&H7000000000000000L) If temporary > -&H7000000000000000L AndAlso UncheckedCLng(temporary) > -&H1000000000000001L Then Return False End If Else If sourceValue > &H7000000000000000L Then Dim temporary As Double = (sourceValue - &H7000000000000000L) If temporary < &H7000000000000000L AndAlso UncheckedCLng(temporary) < &H1000000000000000L Then Return False End If Else Return False End If End If End If Return True End Function Private Function ConvertFloatingToUI64(sourceValue As Double) As Long ' // Conversion from double to uint64 is annoyingly implemented by the ' // VC++ compiler as (uint64)(int64)(double)val, so we have to do it by hand. Dim result As Long ' // code below stolen from jit... Dim two63 As Double = 2147483648.0 * 4294967296.0 If sourceValue < two63 Then result = UncheckedCLng(sourceValue) Else result = UncheckedAdd(UncheckedCLng(sourceValue - two63), &H8000000000000000) End If Return result End Function Private Function IsUnsignedLongType(type As ConstantValueTypeDiscriminator) As Boolean Return type = ConstantValueTypeDiscriminator.UInt64 End Function Friend Function TypeAllowsCompileTimeConversions(type As ConstantValueTypeDiscriminator) As Boolean Return TypeAllowsCompileTimeOperations(type) End Function Friend Function TypeAllowsCompileTimeOperations(type As ConstantValueTypeDiscriminator) As Boolean Select Case (type) Case ConstantValueTypeDiscriminator.Boolean, ConstantValueTypeDiscriminator.SByte, ConstantValueTypeDiscriminator.Byte, ConstantValueTypeDiscriminator.Int16, ConstantValueTypeDiscriminator.UInt16, ConstantValueTypeDiscriminator.Int32, ConstantValueTypeDiscriminator.UInt32, ConstantValueTypeDiscriminator.Int64, ConstantValueTypeDiscriminator.UInt64, ConstantValueTypeDiscriminator.Char, ConstantValueTypeDiscriminator.Decimal, ConstantValueTypeDiscriminator.Double, ConstantValueTypeDiscriminator.Single, ConstantValueTypeDiscriminator.DateTime, ConstantValueTypeDiscriminator.String Return True Case Else Return False End Select End Function Friend Function AdjustConstantValueFromMetadata(value As ConstantValue, targetType As TypeSymbol, isByRefParamValue As Boolean) As ConstantValue ' See MetaImport::DecodeValue in Dev10 compiler. If targetType Is Nothing OrElse targetType.IsErrorType() Then Return value End If Select Case value.Discriminator Case ConstantValueTypeDiscriminator.Int32 ' Adding the test for Object here is necessary in order to ' make something like "Optional Byref X As Object = 5" work. If targetType.IsIntrinsicType() OrElse targetType.IsEnumType() OrElse targetType.IsObjectType() OrElse (targetType.IsNullableType() AndAlso targetType.GetNullableUnderlyingType().IsIntrinsicType()) Then 'No change Exit Select End If If isByRefParamValue OrElse (Not targetType.IsTypeParameter() AndAlso Not targetType.IsArrayType() AndAlso targetType.IsReferenceType()) Then ' // REVIEW: are there other byref types besides Integer and enums ' // that might need to be handled here? ' // ByRef Integer, and ByRef Enum (that is stored as I4) ' // are pointer types, but optional values are not pointers ' // COM+ encodes pointer constants as I4's ' // CONSIDER LATER AnthonyL 8/21/00: Does this t_ref workaround move to I8 on a 64-bit machine? ' // MattGe: Back out part of 604868 to address build lab issue #4093 ' // Probably just need to #ifdef this differently for 64bit, but ' // will let Cameron decide. ' //Value.Integral = (__int32)*(WIN64_UNALIGNED void **)pvValue; If value.Int32Value = 0 Then value = ConstantValue.Nothing Else value = ConstantValue.Bad End If End If Case ConstantValueTypeDiscriminator.Int64 If targetType.IsDateTimeType() Then value = ConstantValue.Create(New DateTime(value.Int64Value)) End If End Select Return value End Function Friend Function Multiply( leftValue As Long, rightValue As Long, sourceType As SpecialType, resultType As SpecialType, ByRef integerOverflow As Boolean ) As Long Return Multiply(leftValue, rightValue, sourceType.ToConstantValueDiscriminator(), resultType.ToConstantValueDiscriminator(), integerOverflow) End Function Friend Function Multiply( leftValue As Long, rightValue As Long, sourceType As ConstantValueTypeDiscriminator, resultType As ConstantValueTypeDiscriminator, ByRef integerOverflow As Boolean ) As Long Dim ResultValue = NarrowIntegralResult( UncheckedMul(leftValue, rightValue), sourceType, resultType, integerOverflow) If ConstantValue.IsUnsignedIntegralType(resultType) Then If rightValue <> 0 AndAlso UncheckedCULng(ResultValue) / UncheckedCULng(rightValue) <> UncheckedCULng(leftValue) Then integerOverflow = True End If Else If (leftValue > 0 AndAlso rightValue > 0 AndAlso ResultValue <= 0) OrElse (leftValue < 0 AndAlso rightValue < 0 AndAlso ResultValue <= 0) OrElse (leftValue > 0 AndAlso rightValue < 0 AndAlso ResultValue >= 0) OrElse (leftValue < 0 AndAlso rightValue > 0 AndAlso ResultValue >= 0) OrElse (rightValue <> 0 AndAlso ResultValue / rightValue <> leftValue) Then integerOverflow = True End If End If Return ResultValue End Function End Module End Namespace