[Bug 38988] .NET applications using System.Decimal to float conversion may return wrong results ('VarR4FromDec' divisor integer overflow)
wine-bugs at winehq.org
wine-bugs at winehq.org
Wed Jul 29 14:31:15 CDT 2015
https://bugs.winehq.org/show_bug.cgi?id=38988
Anastasius Focht <focht at gmx.net> changed:
What |Removed |Added
----------------------------------------------------------------------------
Keywords| |dotnet
Status|UNCONFIRMED |NEW
CC| |focht at gmx.net
Component|-unknown |oleaut32
Summary|when using MS .net there |.NET applications using
|are wrong results (but no |System.Decimal to float
|errors) |conversion may return wrong
| |results ('VarR4FromDec'
| |divisor integer overflow)
Ever confirmed|0 |1
--- Comment #4 from Anastasius Focht <focht at gmx.net> ---
Hello folks,
confirming.
Prerequisite: 'winetricks -q dotnet40'
IL code of the app using 'ILSpy':
--- snip ---
.method private hidebysig static
void Main (
string[] args
) cil managed
{
// Method begins at RVA 0x2050
// Code size 161 (0xa1)
.maxstack 6
.entrypoint
.locals init (
[0] valuetype [mscorlib]System.Decimal,
[1] float32
)
IL_0000: ldc.i4 1353919093
IL_0005: ldc.i4 138
IL_000a: ldc.i4.0
IL_000b: ldc.i4 128
IL_0010: ldc.i4.s 12
IL_0012: newobj instance void [mscorlib]System.Decimal::.ctor(int32, int32,
int32, bool, uint8)
IL_0017: stloc.0
IL_0018: ldloc.0
IL_0019: call float32 [mscorlib]System.Decimal::op_Explicit(valuetype
[mscorlib]System.Decimal)
IL_001e: conv.r4
IL_001f: stloc.1
IL_0020: ldstr "Value as decimal: "
IL_0025: ldloc.0
IL_0026: box [mscorlib]System.Decimal
IL_002b: call string [mscorlib]System.String::Concat(object, object)
IL_0030: call void [mscorlib]System.Console::WriteLine(string)
IL_0035: ldstr "Value converted to float: "
IL_003a: ldloc.1
IL_003b: box [mscorlib]System.Single
IL_0040: call string [mscorlib]System.String::Concat(object, object)
IL_0045: call void [mscorlib]System.Console::WriteLine(string)
IL_004a: ldc.i4 -268880975
IL_004f: ldc.i4 140
IL_0054: ldc.i4.0
IL_0055: ldc.i4.0
IL_0056: ldc.i4.s 12
IL_0058: newobj instance void [mscorlib]System.Decimal::.ctor(int32, int32,
int32, bool, uint8)
IL_005d: stloc.0
IL_005e: ldloc.0
IL_005f: call float32 [mscorlib]System.Decimal::op_Explicit(valuetype
[mscorlib]System.Decimal)
IL_0064: conv.r4
IL_0065: stloc.1
IL_0066: ldstr "Value as decimal: "
IL_006b: ldloc.0
IL_006c: box [mscorlib]System.Decimal
IL_0071: call string [mscorlib]System.String::Concat(object, object)
IL_0076: call void [mscorlib]System.Console::WriteLine(string)
IL_007b: ldstr "Value converted to float: "
IL_0080: ldloc.1
IL_0081: box [mscorlib]System.Single
IL_0086: call string [mscorlib]System.String::Concat(object, object)
IL_008b: call void [mscorlib]System.Console::WriteLine(string)
IL_0090: ldstr "\n<RETURN>"
IL_0095: call void [mscorlib]System.Console::WriteLine(string)
IL_009a: call string [mscorlib]System.Console::ReadLine()
IL_009f: pop
IL_00a0: ret
} // end of method Program::Main
--- snip ---
'Decimal' constructor '(Int32, Int32, Int32, Boolean, Byte)':
https://msdn.microsoft.com/en-us/library/bb1c1a6x.aspx
--- quote ---
public Decimal(
int lo,
int mid,
int hi,
bool isNegative,
byte scale
)
...
Parameters
lo
Type: System.Int32
The low 32 bits of a 96-bit integer.
mid
Type: System.Int32
The middle 32 bits of a 96-bit integer.
hi
Type: System.Int32
The high 32 bits of a 96-bit integer.
isNegative
Type: System.Boolean
true to indicate a negative number; false to indicate a positive number.
scale
Type: System.Byte
A power of 10 ranging from 0 to 28.
...
Remarks
The binary representation of a Decimal number consists of a 1-bit sign, a
96-bit integer number, and a scaling factor used to divide the integer number
and specify what portion of it is a decimal fraction. The scaling factor is
implicitly the number 10 raised to an exponent ranging from 0 to 28.
--- quote ---
The first number -0.594059405941:
--- snip ---
IL_0000: ldc.i4 1353919093
IL_0005: ldc.i4 138
IL_000a: ldc.i4.0
IL_000b: ldc.i4 128
IL_0010: ldc.i4.s 12
--- snip ---
Using 'bc' command line tool to check the compiler did the right thing on
emitting DECIMAL parts for '-0.594059405941m':
--- snip ---
$ echo "scale=20; -(138*2^32+1353919093)/10^12" | bc
-.59405940594100000000
--- snip ---
Yep.
--- snip ---
$ Wine-dbg>info locals
0x7e679c3f VarR4FromDec+0x3d: (0033f228)
DECIMAL* pDecIn=0x33f23c (parameter [EBP+8])
float* pFltOut=0x33f238 (parameter [EBP+12])
BYTE scale=12 (local [ESP+39])
int divisor=0x1 (local [ESP+32])
double highPart=...(local [ESP+24])
Wine-dbg>p *pDecIn
{wReserved=0, u={s={scale=12, sign=-128}, signscale=0x800c}, Hi32=0,
u1={s1={Lo32=0x50b32a75, Mid32=0x8a}, Lo64=0x8a50b32a75}}
--- snip ---
Source:
https://source.winehq.org/git/wine.git/blob/bedd444a3616fea54a060e07c27a137f29052fc9:/dlls/oleaut32/vartype.c#l2948
--- snip ---
2948 HRESULT WINAPI VarR4FromDec(DECIMAL* pDecIn, float *pFltOut)
2949 {
2950 BYTE scale = DEC_SCALE(pDecIn);
2951 int divisor = 1;
2952 double highPart;
2953
2954 if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
2955 return E_INVALIDARG;
2956
2957 while (scale--)
2958 divisor *= 10;
2959
2960 if (DEC_SIGN(pDecIn))
2961 divisor = -divisor;
2962
2963 if (DEC_HI32(pDecIn))
2964 {
2965 highPart = (double)DEC_HI32(pDecIn) / (double)divisor;
2966 highPart *= 4294967296.0F;
2967 highPart *= 4294967296.0F;
2968 }
2969 else
2970 highPart = 0.0;
2971
2972 *pFltOut = (double)DEC_LO64(pDecIn) / (double)divisor + highPart;
2973 return S_OK;
2974 }
--- snip ---
Integer overflow for divisor. The data type must cover a range of at least
-1e+28..1e+28 here.
$ wine --version
wine-1.7.48
Regards
--
Do not reply to this email, post in Bugzilla using the
above URL to reply.
You are receiving this mail because:
You are watching all bug changes.
More information about the wine-bugs
mailing list