How can we help you today? How can we help you today?

Bug with disassembling of not-a-number (NaN) when boxed

When disassembling code (with .NET Reflector version 5.1.3.0, for at least the C# language) that references System.Double.NaN or System.Single.NaN fields in the special case where the values are boxed as objects, the generated code is wrong because it is equivalent to System.Double.PositiveInfinity or System.Single.PositiveInfinity, respectively. This can easily be verified, since one can assert during runtime that "float.NaN != float.PositiveInfinity" and "double.NaN != double.PositiveInfinity", although this won't be the case for the disassembled code.

The following code is provided as an example that illustrates the problem.

Original...
using System;
using System.Diagnostics;
public class Program
{
    public static object GetDoubleBoxed(int id)
    {
        switch (id)
        {
            case -1:
                return double.NegativeInfinity;  // Disassembles okay
            case 1:
                return double.PositiveInfinity;  // Disassembles okay
        }
        return double.NaN;  // Disassembles WRONG!!!
    }
    public static double GetDoubleValue(int id)  // Disassembles exactly
    {
        switch (id)
        {
            case -1:
                return double.NegativeInfinity;
            case 1:
                return double.PositiveInfinity;
        }
        return double.NaN;
    }
    public static object GetSingleBoxed(int id)
    {
        switch (id)
        {
            case -1:
                return float.NegativeInfinity;  // Disassembles okay
            case 1:
                return float.PositiveInfinity;  // Disassembles okay
        }
        return float.NaN;  // Disassembles WRONG!!!
    }
    public static float GetSingleValue(int id)  // Disassembles exactly
    {
        switch (id)
        {
            case -1:
                return float.NegativeInfinity;
            case 1:
                return float.PositiveInfinity;
        }
        return float.NaN;
    }
    public static void Main()
    {
        float valueSingleNaN = float.NaN;  // Disassembles exactly
        object boxedSingleNaN = float.NaN;  // Disassembles WRONG!!!
        float valueSingleInf = float.PositiveInfinity;  // Disassembles exactly
        object boxedSingleInf = float.PositiveInfinity;  // Disassembles okay
        Trace.Assert(valueSingleNaN != valueSingleInf);  // Disassembles exactly
        Trace.Assert(valueSingleInf == ((float)1.0 / (float)0.0));  // Disassembles okay
        Trace.Assert(((float)boxedSingleNaN) != ((float)boxedSingleInf));  // Disassembles exactly, but would FAIL at runtime for recompiled disassembly!!!
        Trace.Assert(((float)boxedSingleInf) == ((float)1.0 / (float)0.0));  // Disassembles okay
        double valueDoubleNaN = double.NaN;  // Disassembles exactly
        object boxedDoubleNaN = double.NaN;  // Disassembles WRONG!!!
        double valueDoubleInf = double.PositiveInfinity;  // Disassembles exactly
        object boxedDoubleInf = double.PositiveInfinity;  // Disassembles okay
        Trace.Assert(valueDoubleNaN != valueDoubleInf);  // Disassembles exactly
        Trace.Assert(valueDoubleInf == ((double)1.0 / (double)0.0));  // Disassembles okay
        Trace.Assert(((double)boxedDoubleNaN) != ((double)boxedDoubleInf));  // Disassembles exactly, but would FAIL at runtime for recompiled disassembly!!!
        Trace.Assert(((double)boxedDoubleInf) == ((double)1.0 / (double)0.0));  // Disassembles okay
    }
}

Generated...
using System;
using System.Diagnostics;
public class Program
{
    public static object GetDoubleBoxed(int id)
    {
        switch (id)
        {
            case -1:
                return (double)-1.0 / (double)0.0;
            case 1:
                return (double)1.0 / (double)0.0;
        }
        return (double)1.0 / (double)0.0;
    }
    public static double GetDoubleValue(int id)
    {
        switch (id)
        {
            case -1:
                return double.NegativeInfinity;
            case 1:
                return double.PositiveInfinity;
        }
        return double.NaN;
    }
    public static object GetSingleBoxed(int id)
    {
        switch (id)
        {
            case -1:
                return (float)-1.0 / (float)0.0;
            case 1:
                return (float)1.0 / (float)0.0;
        }
        return (float)1.0 / (float)0.0;
    }
    public static float GetSingleValue(int id)
    {
        switch (id)
        {
            case -1:
                return float.NegativeInfinity;
            case 1:
                return float.PositiveInfinity;
        }
        return float.NaN;
    }
    public static void Main()
    {
        float valueSingleNaN = float.NaN;
        object boxedSingleNaN = (float)1.0 / (float)0.0;
        float valueSingleInf = float.PositiveInfinity;
        object boxedSingleInf = (float)1.0 / (float)0.0;
        Trace.Assert(valueSingleNaN != valueSingleInf);
        Trace.Assert(valueSingleInf == float.PositiveInfinity);
        Trace.Assert(((float)boxedSingleNaN) != ((float)boxedSingleInf));
        Trace.Assert(((float)boxedSingleInf) == float.PositiveInfinity);
        double valueDoubleNaN = double.NaN;
        object boxedDoubleNaN = (double)1.0 / (double)0.0;
        double valueDoubleInf = double.PositiveInfinity;
        object boxedDoubleInf = (double)1.0 / (double)0.0;
        Trace.Assert(valueDoubleNaN != valueDoubleInf);
        Trace.Assert(valueDoubleInf == double.PositiveInfinity);
        Trace.Assert(((double)boxedDoubleNaN) != ((double)boxedDoubleInf));
        Trace.Assert(((double)boxedDoubleInf) == double.PositiveInfinity);
    }
}
TAG
0

Add comment

Please sign in to leave a comment.