Testing for a float NaN results in a stack overflow

前端 未结 3 851
广开言路
广开言路 2020-12-31 11:40

C#, VS 2010

I need to determine if a float value is NaN.

Testing a float for NaN using

float.IsNaN(aFloatNumber) 

crashes

3条回答
  •  长发绾君心
    2020-12-31 11:50

    The solution:

    First of all, thank you to @Matt for pointing me in the right direction, and @Hans Passant for providing the workaround.

    The application talks to a CAN-USB adapter from Chinese manufacturer QM_CAN.

    The problem is in their driver.

    The DLL statements and Driver import:

       // DLL Statement
        IntPtr QM_DLL;
        TYPE_Init_can Init_can;
        TYPE_Quit_can Quit_can;
        TYPE_Can_send Can_send;
        TYPE_Can_receive Can_receive;
        delegate int TYPE_Init_can(byte com_NUM, byte Model, int CanBaudRate, byte SET_ID_TYPE, byte FILTER_MODE, byte[] RXF, byte[] RXM);
        delegate int TYPE_Quit_can();
        delegate int TYPE_Can_send(byte[] IDbuff, byte[] Databuff, byte FreamType, byte Bytes);
        delegate int TYPE_Can_receive(byte[] IDbuff, byte[] Databuff, byte[] FreamType, byte[] Bytes);
    
        // Driver
        [DllImport("kernel32.dll")]
        static extern IntPtr LoadLibrary(string lpFileName);
        [DllImport("kernel32.dll")]
        static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
    

    The call to the offending code, including Hans' workaround:

       private void InitCanUsbDLL() // Initiate the driver for the CAN-USB dongle
        {
    
            // Here is an example of dynamically loaded DLL functions
            QM_DLL = LoadLibrary("QM_USB.dll");
            if (QM_DLL != IntPtr.Zero)
            {
                IntPtr P_Init_can = GetProcAddress(QM_DLL, "Init_can");
                IntPtr P_Quit_can = GetProcAddress(QM_DLL, "Quit_can");
                IntPtr P_Can_send = GetProcAddress(QM_DLL, "Can_send");
                IntPtr P_Can_receive = GetProcAddress(QM_DLL, "Can_receive");
                // The next line results in a FPU stack overflow if float.NaN is called by a handler
                Init_can = (TYPE_Init_can)Marshal.GetDelegateForFunctionPointer(P_Init_can, typeof(TYPE_Init_can));
                // Reset the FPU, otherwise we get a stack overflow when we work with float.NaN within a event handler
                // Thanks to Matt for pointing me in the right direction and to Hans Passant for this workaround:
                // http://stackoverflow.com/questions/25205112/testing-for-a-float-nan-results-in-a-stack-overflow/25206025
                try { throw new Exception("Please ignore, resetting FPU"); }
                catch { } 
                Quit_can = (TYPE_Quit_can)Marshal.GetDelegateForFunctionPointer(P_Quit_can, typeof(TYPE_Quit_can));
                Can_send = (TYPE_Can_send)Marshal.GetDelegateForFunctionPointer(P_Can_send, typeof(TYPE_Can_send));
                Can_receive = (TYPE_Can_receive)Marshal.GetDelegateForFunctionPointer(P_Can_receive, typeof(TYPE_Can_receive));
            }
        }
    

    The reason that the application crashed when a reference was made to float.NaN in the event handler and not in the constructor was a simple matter of timing: the constructor is called before InitCanUsbDLL(), but the event handler was called long after InitCanUsbDLL() corrupted the FPU registers.

提交回复
热议问题