You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
163 lines
3.5 KiB
163 lines
3.5 KiB
/*++
|
|
|
|
Copyright (c) Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
rtloverflow.c
|
|
|
|
Abstract:
|
|
|
|
32bit/64bit signed/unsigned add/multiply with overflow checking
|
|
|
|
Author:
|
|
|
|
Jay Krell (JayKrell) January 2002
|
|
|
|
Revision History:
|
|
|
|
Environment:
|
|
|
|
anywhere, only dependency is STATUS_SUCCESS, STATUS_INTEGER_OVERFLOW
|
|
Initial client is win32k.sys font loading "rewrite".
|
|
|
|
--*/
|
|
|
|
#include "ntos.h"
|
|
#include "nt.h"
|
|
#include "ntstatus.h"
|
|
#include "ntrtloverflow.h"
|
|
|
|
//
|
|
// add functions are FORCEINLINE in ntrtl.h
|
|
//
|
|
|
|
NTSTATUS
|
|
RtlpAddWithOverflowCheckUnsigned64(
|
|
unsigned __int64 *pc,
|
|
unsigned __int64 a,
|
|
unsigned __int64 b
|
|
)
|
|
{
|
|
return RtlUnsignedAddWithCarryOut64(pc, a, b) ? STATUS_INTEGER_OVERFLOW : STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlMultiplyWithOverflowCheckSigned32(
|
|
__int32 * pc,
|
|
__int32 a,
|
|
__int32 b
|
|
)
|
|
{
|
|
__int64 c;
|
|
|
|
c = ((__int64)a) * ((__int64)b);
|
|
*pc = (__int32)c;
|
|
c &= 0xFFFFFFFF80000000ui64;
|
|
if ((a < 0) != (b < 0))
|
|
{
|
|
return (c == 0xFFFFFFFF80000000ui64) ? STATUS_SUCCESS : STATUS_INTEGER_OVERFLOW;
|
|
}
|
|
else
|
|
{
|
|
return (c == 0) ? STATUS_SUCCESS : STATUS_INTEGER_OVERFLOW;
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlMultiplyWithOverflowCheckUnsigned32(
|
|
unsigned __int32 * pc,
|
|
unsigned __int32 a,
|
|
unsigned __int32 b
|
|
)
|
|
{
|
|
unsigned __int64 c;
|
|
|
|
c = ((unsigned __int64)a) * ((unsigned __int64)b);
|
|
*pc = (unsigned __int32)c;
|
|
c &= 0xFFFFFFFF00000000ui64;
|
|
return (c == 0) ? STATUS_SUCCESS : STATUS_INTEGER_OVERFLOW;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlMultiplyWithOverflowCheckUnsigned64(
|
|
unsigned __int64 * pc,
|
|
unsigned __int64 a,
|
|
unsigned __int64 b
|
|
)
|
|
{
|
|
unsigned __int64 ah;
|
|
unsigned __int64 al;
|
|
unsigned __int64 bh;
|
|
unsigned __int64 bl;
|
|
unsigned __int64 c;
|
|
unsigned __int64 m;
|
|
NTSTATUS Status;
|
|
|
|
ah = (a >> 32);
|
|
bh = (b >> 32);
|
|
|
|
//
|
|
// 09 * 09 = 81 => no overflow
|
|
//
|
|
if (ah == 0 && bh == 0)
|
|
{
|
|
*pc = (a * b);
|
|
Status = STATUS_SUCCESS;
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// 10 * 10 = 100 => overflow
|
|
//
|
|
if (bh != 0 && ah != 0)
|
|
{
|
|
Status = STATUS_INTEGER_OVERFLOW;
|
|
goto Exit;
|
|
}
|
|
|
|
al = (a & 0xFFFFFFFFui64);
|
|
bl = (b & 0xFFFFFFFFui64);
|
|
|
|
//
|
|
// a * b = al * bl + (al * bh) * "10" + (ah * bl) * "10" + (ah * bh) * "100"
|
|
//
|
|
c = (al * bl);
|
|
m = (ah * bl);
|
|
if ((m & 0xFFFFFFFF00000000ui64) != 0) {
|
|
//
|
|
// for example: 90 * 09 => overflow
|
|
// 09 * 09 => 81, 8 != 0 => overflow
|
|
//
|
|
// ah != 0 or bh != 0 very often but not always leads to overflow
|
|
// 40 * 2 is ok, but 40 * 3 and 50 * 2 are not
|
|
//
|
|
Status = STATUS_INTEGER_OVERFLOW;
|
|
goto Exit;
|
|
}
|
|
if (!NT_SUCCESS(Status = RtlpAddWithOverflowCheckUnsigned64(&c, c, m << 32))) {
|
|
goto Exit;
|
|
}
|
|
m = (al * bh);
|
|
if ((m & 0xFFFFFFFF00000000ui64) != 0) {
|
|
//
|
|
// for example: 09 * 90 => overflow
|
|
// 09 * 09 => 81, 8 != 0 => overflow
|
|
//
|
|
// ah != 0 or bh != 0 very often but not always leads to overflow
|
|
// 40 * 2 is ok, but 40 * 3 and 50 * 2 are not
|
|
//
|
|
Status = STATUS_INTEGER_OVERFLOW;
|
|
goto Exit;
|
|
}
|
|
if (!NT_SUCCESS(Status = RtlpAddWithOverflowCheckUnsigned64(&c, c, m << 32))) {
|
|
goto Exit;
|
|
}
|
|
*pc = c;
|
|
Status = STATUS_SUCCESS;
|
|
Exit:
|
|
return Status;
|
|
}
|