https://bugs.winehq.org/show_bug.cgi?id=38988
Bug ID: 38988 Summary: when using MS .net there are wrong results (but no errors) Product: Wine Version: 1.6.2 Hardware: x86-64 OS: Linux Status: UNCONFIRMED Severity: major Priority: P2 Component: -unknown Assignee: wine-bugs@winehq.org Reporter: mayth@arcor.de Distribution: ---
Created attachment 51943 --> https://bugs.winehq.org/attachment.cgi?id=51943 executable showing the results of the code quoted above
The bug was detected on a system as follows: * Linux Mint 17 64-bit * Wine 1.6.2 with a 32-bit environment * orginal Microsoft .net framework installed in Wine (irrelevant if V2 or V3.5 or V4, irrelevant if installed directly or using winetricks)
If a .net program written in C# and running on a system as described above uses an explicit conversion from "decimal" data type to "float" data type, this conversion sometimes gives wrong results. There is no error message at all, but the result is completely wrong i.e. it is not just a matter of rounding. However, the result is not always wrong, but only for certain numbers (see below).
The same program executed on a Windows system or on a Linux system with Mono works fine. Therefore, the program seems to call some functions within the original MS .net framework which are not correctly executed by Wine.
The C# code which demonstrates the bug is as follows:
// example #1 decimal d = -0.594059405941m; float f = (float) d; Console.WriteLine ( "Value as decimal: " + d ); Console.WriteLine ( "Value converted to float: " + f ); // example #2 d = 0.605321507761m; f = (float) d; Console.WriteLine ( "Value as decimal: " + d ); Console.WriteLine ( "Value converted to float: " + f );
A compiled file is attached. Run it on a Windows system or on a Linux system with Mono, and it works fine. Run it using Wine with the original MS .net framework, and the bug will occur.
https://bugs.winehq.org/show_bug.cgi?id=38988
Sebastian Lackner sebastian@fds-team.de changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |sebastian@fds-team.de Severity|major |normal
--- Comment #1 from Sebastian Lackner sebastian@fds-team.de --- You are testing with a very outdated version of Wine, 1.6.2 is over one year old. Please make sure if the problem also occurs with the current development version 1.7.48. If possible, please also attach the full source of your testcase.
https://bugs.winehq.org/show_bug.cgi?id=38988
--- Comment #2 from Tom May mayth@arcor.de --- Created attachment 51950 --> https://bugs.winehq.org/attachment.cgi?id=51950 complete C# source file
This is the complete C# source file. It needs to be compiled by Visual Studio. As you can see, the source file mainly consists of the part which was quoted in the bug description.
https://bugs.winehq.org/show_bug.cgi?id=38988
--- Comment #3 from Tom May mayth@arcor.de --- P.S.: I have tested the attached program with Wine 1.7.44 The result ist identical to the result achieved with 1.6.2 stable.
https://bugs.winehq.org/show_bug.cgi?id=38988
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- Keywords| |dotnet Status|UNCONFIRMED |NEW CC| |focht@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@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/bedd444a3616fea54a060e07c27a137f...
--- 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
https://bugs.winehq.org/show_bug.cgi?id=38988
--- Comment #5 from Sebastian Lackner sebastian@fds-team.de --- This should be fixed with http://source.winehq.org/git/wine.git/commit/728076223812e11441f1f185c30d836..., please retest.
https://bugs.winehq.org/show_bug.cgi?id=38988
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- Keywords| |testcase Fixed by SHA1| |728076223812e11441f1f185c30 | |d836c1269712e Status|NEW |RESOLVED Resolution|--- |FIXED
--- Comment #6 from Anastasius Focht focht@gmx.net --- Hello folks,
this is fixed by commit https://source.winehq.org/git/wine.git/commitdiff/728076223812e11441f1f185c3...
Thanks Sebastian
--- snip --- $ wine ./Conversion\ decimal\ to\ float.exe ... Value as decimal: -0.594059405941 Value converted to float: -0.5940594 Value as decimal: 0.605321507761 Value converted to float: 0.6053215 --- snip ---
Regards
https://bugs.winehq.org/show_bug.cgi?id=38988
Alexandre Julliard julliard@winehq.org changed:
What |Removed |Added ---------------------------------------------------------------------------- Status|RESOLVED |CLOSED
--- Comment #7 from Alexandre Julliard julliard@winehq.org --- Closing bugs fixed in 1.7.50.