Windows System Software -- Consulting, Training, Development -- Unique Expertise, Guaranteed Results

Home NTDEV

Before Posting...

Please check out the Community Guidelines in the Announcements and Administration Category.

More Info on Driver Writing and Debugging


The free OSR Learning Library has more than 50 articles on a wide variety of topics about writing and debugging device drivers and Minifilters. From introductory level to advanced. All the articles have been recently reviewed and updated, and are written using the clear and definitive style you've come to expect from OSR over the years.


Check out The OSR Learning Library at: https://www.osr.com/osr-learning-library/


Why do I keep on getting floating point warning even after using FloatingPointState?

sn99sn99 Member Posts: 13
edited December 2022 in NTDEV

The code in question is:

#include "ShanonEntropy.h"

constexpr DOUBLE M_LOG2E = 1.4426950408889634;

constexpr ULONG MAX_BYTE_SIZE = 256;

_Kernel_float_used_ DOUBLE shannonEntropy(PUCHAR buffer, size_t size)
{
    if (IS_DEBUG_IRP)
        DbgPrint("!!! snFilter: Calc entropy started\n");
    DOUBLE entropy = 0.0;
    ULONG bucketByteVals[MAX_BYTE_SIZE] = {};
    for (ULONG i = 0; i < size; i++)
    {
        bucketByteVals[buffer[i]]++;
    }

    KFLOATING_SAVE SaveState;
    __try
    {
        KeSaveFloatingPointState(&SaveState);
        for (ULONG i = 0; i < MAX_BYTE_SIZE; i++)
        {
            if (bucketByteVals[i] != 0)
            {
                DOUBLE
                val = (DOUBLE)bucketByteVals[i] / (DOUBLE)size;
                entropy += (-1) * val * log(val) * M_LOG2E;
            }
        }
    }
    __finally
    {
        KeRestoreFloatingPointState(&SaveState);
    }
    return entropy;
}

I am using it like:

KFLOATING_SAVE SaveState;
 __try
 {
        KeSaveFloatingPointState(&SaveState);
        newItem->Entropy = shannonEntropy((PUCHAR)writeBuffer, newItem->MemSizeUsed);
        newItem->isEntropyCalc = TRUE;
}
 __except (EXCEPTION_EXECUTE_HANDLER)
{
        KeRestoreFloatingPointState(&SaveState);
        if (IS_DEBUG_IRP)
        DbgPrint("!!! snFilter: Failed to calc entropy\n");
        delete newEntry;
        // fail the irp request
        Data->IoStatus.Status = STATUS_INTERNAL_ERROR;
        Data->IoStatus.Information = 0;
        return FLT_PREOP_COMPLETE;
}
Post edited by sn99 on

Comments

  • Peter_Viscarola_(OSR)Peter_Viscarola_(OSR) Administrator Posts: 9,055

    Well, you don't tell us what warning your getting, or even what COMPONENT is giving you the warning (the compiler, Code Analysis, SDV, what!?). But... regardless... your code above is pretty odd. You have the Floating Point State, then call a function that saves the FP state again, does an FP operation, then restores the FP state and returns to the caller... where you don't then restore the FP state?

    So... there's no reason to save the FP state twice, that's pretty obvious.

    In fact, if this code is on an x64 (or ARM64) system, you don't need to save the FP state at all.

    Does that help? If not, please be more specific about the "warning" that you're getting.

    Peter Viscarola
    OSR
    @OSRDrivers

  • sn99sn99 Member Posts: 13
    > @"Peter_Viscarola_(OSR)" said:
    > Well, you don't tell us what warning your getting, or even what COMPONENT is giving you the warning (the compiler, Code Analysis, SDV, what!?). But... regardless... your code above is pretty odd. You have the Floating Point State, then call a function that saves the FP state again, does an FP operation, then restores the FP state and returns to the caller... where you don't then restore the FP state?
    >
    > So... there's no reason to save the FP state twice, that's pretty obvious.
    >
    > In fact, if this code is on an x64 (or ARM64) system, you don't need to save the FP state at all.
    >
    > Does that help? If not, please be more specific about the "warning" that you're getting.

    Ah my bad, apologies. It was this error: "warning C28110: Drivers must protect floating point hardware state. See use of float entropy: Use KeSaveFloatingPointState/KeRestoreFloatingPointState around floating point operations. Display Drivers should use the corresponding Eng... routines."

    This occurs at line "return entropy".

    I understand that it causes no issue on x64, but is there a way to fix it for x86 machines by modifying shannonEntropy?

    I get the same error even if I remove KeSaveFloatingPointState and KeRestoreFloatingPointState from call site.
  • Tim_RobertsTim_Roberts Member - All Emails Posts: 14,445

    The warning is correct, and it is pointing to the right spot -- you are, in fact, using floating point registers outside of your save/restore block. Remember that your "return entropy;" statement will return the value in a floating point register (FP(0) or XMM0). To be proper, you need to have your KeSave/Restore outside of this function. You can't do it inside.

    Tim Roberts, [email protected]
    Providenza & Boekelheide, Inc.

  • sn99sn99 Member Posts: 13
    > @Tim_Roberts said:
    > The warning is correct, and it is pointing to the right spot -- you are, in fact, using floating point registers outside of your save/restore block. Remember that your "return entropy;" statement will return the value in a floating point register (FP(0) or XMM0). To be proper, you need to have your KeSave/Restore outside of this function. You can't do it inside.

    So basically something like this:

    ```
    #include "ShanonEntropy.h"

    constexpr DOUBLE M_LOG2E = 1.4426950408889634;

    constexpr ULONG MAX_BYTE_SIZE = 256;

    _Kernel_float_used_ DOUBLE shannonEntropy(PUCHAR buffer, size_t size)
    {
    if (IS_DEBUG_IRP)
    DbgPrint("!!! snFilter: Calc entropy started\n");
    DOUBLE entropy = 0.0;
    ULONG bucketByteVals[MAX_BYTE_SIZE] = {};
    for (ULONG i = 0; i < size; i++)
    {
    bucketByteVals[buffer[i]]++;
    }

    __try
    {
    for (ULONG i = 0; i < MAX_BYTE_SIZE; i++)
    {
    if (bucketByteVals[i] != 0)
    {
    DOUBLE
    val = (DOUBLE)bucketByteVals[i] / (DOUBLE)size;
    entropy += (-1) * val * log(val) * M_LOG2E;
    }
    }
    }
    __finally
    {}
    return entropy;
    }
    ```

    And:

    ```
    KFLOATING_SAVE SaveState;
    KeSaveFloatingPointState(&SaveState);
    __try
    {
    newItem->Entropy = shannonEntropy((PUCHAR)writeBuffer, newItem->MemSizeUsed);
    newItem->isEntropyCalc = TRUE;
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
    if (IS_DEBUG_IRP)
    DbgPrint("!!! snFilter: Failed to calc entropy\n");
    delete newEntry;
    // fail the irp request
    Data->IoStatus.Status = STATUS_INTERNAL_ERROR;
    Data->IoStatus.Information = 0;
    return FLT_PREOP_COMPLETE;
    }
    KeRestoreFloatingPointState(&SaveState);
    ```

    ? I am currently away from my machine to test this.
  • sn99sn99 Member Posts: 13

    @sn99 said:

    @Tim_Roberts said:
    The warning is correct, and it is pointing to the right spot -- you are, in fact, using floating point registers outside of your save/restore block. Remember that your "return entropy;" statement will return the value in a floating point register (FP(0) or XMM0). To be proper, you need to have your KeSave/Restore outside of this function. You can't do it inside.

    So basically something like this:

    #include "ShanonEntropy.h"
    
    constexpr DOUBLE M_LOG2E = 1.4426950408889634;
    
    constexpr ULONG MAX_BYTE_SIZE = 256;
    
    _Kernel_float_used_ DOUBLE shannonEntropy(PUCHAR buffer, size_t size)
    {
        if (IS_DEBUG_IRP)
            DbgPrint("!!! snFilter: Calc entropy started\n");
        DOUBLE entropy = 0.0;
        ULONG bucketByteVals[MAX_BYTE_SIZE] = {};
        for (ULONG i = 0; i < size; i++)
        {
            bucketByteVals[buffer[i]]++;
        }
    
        __try
        {
            for (ULONG i = 0; i < MAX_BYTE_SIZE; i++)
            {
                if (bucketByteVals[i] != 0)
                {
                    DOUBLE
                    val = (DOUBLE)bucketByteVals[i] / (DOUBLE)size;
                    entropy += (-1) * val * log(val) * M_LOG2E;
                }
            }
        }
        __finally
        {}
        return entropy;
    }
    

    And:

    KFLOATING_SAVE SaveState;
    KeSaveFloatingPointState(&SaveState);
     __try
     {
            newItem->Entropy = shannonEntropy((PUCHAR)writeBuffer, newItem->MemSizeUsed);
            newItem->isEntropyCalc = TRUE;
    }
     __except (EXCEPTION_EXECUTE_HANDLER)
    {
            if (IS_DEBUG_IRP)
            DbgPrint("!!! snFilter: Failed to calc entropy\n");
            delete newEntry;
            // fail the irp request
            Data->IoStatus.Status = STATUS_INTERNAL_ERROR;
            Data->IoStatus.Information = 0;
            return FLT_PREOP_COMPLETE;
    }
    KeRestoreFloatingPointState(&SaveState);
    

    ? I am currently away from my machine to test this.

    I tested it and with a few changes it now works as intended:

    #include "ShanonEntropy.h"
    
    constexpr DOUBLE M_LOG2E = 1.4426950408889634;
    
    constexpr ULONG MAX_BYTE_SIZE = 256;
    
    _Kernel_float_used_ DOUBLE shannonEntropy(PUCHAR buffer, size_t size)
    {
        if (IS_DEBUG_IRP)
            DbgPrint("!!! snFilter: Calc entropy started\n");
        DOUBLE entropy = 0.0;
        ULONG bucketByteVals[MAX_BYTE_SIZE] = {};
        for (ULONG i = 0; i < size; i++)
        {
            bucketByteVals[buffer[i]]++;
        }
    
        __try
        {
            for (ULONG i = 0; i < MAX_BYTE_SIZE; i++)
            {
                if (bucketByteVals[i] != 0)
                {
                    DOUBLE
                    val = (DOUBLE)bucketByteVals[i] / (DOUBLE)size;
                    entropy += (-1) * val * log(val) * M_LOG2E;
                }
            }
        }
        __finally
        {
        }
    
        return entropy;
    }
    
            __try
            {
                KFLOATING_SAVE SaveState;
                NTSTATUS Status = KeSaveFloatingPointState(&SaveState);
                if (NT_SUCCESS(Status))
                {
                    newItem->Entropy = shannonEntropy((PUCHAR)writeBuffer, newItem->MemSizeUsed);
                }
    
                KeRestoreFloatingPointState(&SaveState);
                newItem->isEntropyCalc = TRUE;
            }
    

    Thanks for pointing in the right direction.

  • MBond2MBond2 Member Posts: 515

    if you are going to use SEH, then you really should use it properly

    NTSTATUS Status = KeSaveFloatingPointState(&SaveState);
    if (!NT_SUCCESS(Status))
    {
    return some_failure_code;
    }
    __try
    {
    newItem->Entropy = shannonEntropy((PUCHAR)writeBuffer, newItem->MemSizeUsed);
    }
    __finally
    {
    KeRestoreFloatingPointState(&SaveState);
    }
    if(newItem->Entropy == SOME_VALUE_THAT_INDICATES_FAILURE)
    {
    return some_other_failure_code;
    }
    return success_code;

    Or don't use SEH at all in this sequence. You don't really need it. What kind of exception do you expect to be thrown from this code? And if one is thrown, what kind of recovery do you think is possible?

    It is reasonable to use the try finally sequence to ensure that resources that are acquired are always freed even in code that can't possibly throw or recover from an exception. But don't use try finally with an empty finally handler and don't use try catch with a sequence that skips KeRestoreFloatingPointState

  • sn99sn99 Member Posts: 13

    @MBond2 said:
    if you are going to use SEH, then you really should use it properly

    NTSTATUS Status = KeSaveFloatingPointState(&SaveState);
    if (!NT_SUCCESS(Status))
    {
    return some_failure_code;
    }
    __try
    {
    newItem->Entropy = shannonEntropy((PUCHAR)writeBuffer, newItem->MemSizeUsed);
    }
    __finally
    {
    KeRestoreFloatingPointState(&SaveState);
    }
    if(newItem->Entropy == SOME_VALUE_THAT_INDICATES_FAILURE)
    {
    return some_other_failure_code;
    }
    return success_code;

    Or don't use SEH at all in this sequence. You don't really need it. What kind of exception do you expect to be thrown from this code? And if one is thrown, what kind of recovery do you think is possible?

    It is reasonable to use the try finally sequence to ensure that resources that are acquired are always freed even in code that can't possibly throw or recover from an exception. But don't use try finally with an empty finally handler and don't use try catch with a sequence that skips KeRestoreFloatingPointState

    Heyo, thanks for the catch, I will make these suggested changes.

    Ah, not exactly my code, my am modifying existing code and hope not to break anything.

Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. Sign in or register to get started.

Upcoming OSR Seminars
OSR has suspended in-person seminars due to the Covid-19 outbreak. But, don't miss your training! Attend via the internet instead!
Kernel Debugging 30 January 2023 Live, Online
Developing Minifilters 20 March 2023 Live, Online
Internals & Software Drivers 17 April 2023 Live, Online
Writing WDF Drivers 22 May 2023 Live, Online