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

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;
}

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.

1 Like

> @“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.

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.

1 Like

> @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.

@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.

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

1 Like

@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.