#ifndef _NTINTSAFE_H_INCLUDED_
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES)
//
// ULONGLONG multiplication
//
_Must_inspect_result_
__inline
NTSTATUS
RtlULongLongMult(
_In_ ULONGLONG ullMultiplicand,
_In_ ULONGLONG ullMultiplier,
_Out_ _Deref_out_range_(==, ullMultiplicand * ullMultiplier) ULONGLONG* pullResult)
{
NTSTATUS status;
#if defined(_USE_INTRINSIC_MULTIPLY128)
ULONGLONG ullResultHigh;
ULONGLONG ullResultLow;
ullResultLow = UnsignedMultiply128(ullMultiplicand, ullMultiplier, &ullResultHigh);
if (ullResultHigh == 0)
{
_Analysis_assume_(ullMultiplicand * ullMultiplier == ullResultLow);
*pullResult = ullResultLow;
status = STATUS_SUCCESS;
}
else
{
*pullResult = ULONGLONG_ERROR;
status = STATUS_INTEGER_OVERFLOW;
}
#else
// 64x64 into 128 is like 32.32 x 32.32.
//
// a.b * c.d = a*(c.d) + .b*(c.d) = a*c + a*.d + .b*c + .b*.d
// back in non-decimal notation where A=a*2^32 and C=c*2^32:
// A*C + A*d + b*C + b*d
// So there are four components to add together.
// result = (a*c*2^64) + (a*d*2^32) + (b*c*2^32) + (b*d)
//
// a * c must be 0 or there would be bits in the high 64-bits
// a * d must be less than 2^32 or there would be bits in the high 64-bits
// b * c must be less than 2^32 or there would be bits in the high 64-bits
// then there must be no overflow of the resulting values summed up.
ULONG dw_a;
ULONG dw_b;
ULONG dw_c;
ULONG dw_d;
ULONGLONG ad = 0;
ULONGLONG bc = 0;
ULONGLONG bd = 0;
ULONGLONG ullResult = 0;
status = STATUS_INTEGER_OVERFLOW;
dw_a = (ULONG)(ullMultiplicand >> 32);
dw_c = (ULONG)(ullMultiplier >> 32);
// common case -- if high dwords are both zero, no chance for overflow
if ((dw_a == 0) && (dw_c == 0))
{
dw_b = (DWORD)ullMultiplicand;
dw_d = (DWORD)ullMultiplier;
*pullResult = (((ULONGLONG)dw_b) * (ULONGLONG)dw_d);
status = STATUS_SUCCESS;
}
else
{
// a * c must be 0 or there would be bits set in the high 64-bits
if ((dw_a == 0) ||
(dw_c == 0))
{
dw_d = (DWORD)ullMultiplier;
// a * d must be less than 2^32 or there would be bits set in the high 64-bits
ad = (((ULONGLONG)dw_a) * (ULONGLONG)dw_d);
if ((ad & 0xffffffff00000000) == 0)
{
dw_b = (DWORD)ullMultiplicand;
// b * c must be less than 2^32 or there would be bits set in the high 64-bits
bc = (((ULONGLONG)dw_b) * (ULONGLONG)dw_c);
if ((bc & 0xffffffff00000000) == 0)
{
// now sum them all up checking for overflow.
// shifting is safe because we already checked for overflow above
if (NT_SUCCESS(RtlULongLongAdd(bc << 32, ad << 32, &ullResult)))
{
// b * d
bd = (((ULONGLONG)dw_b) * (ULONGLONG)dw_d);
if (NT_SUCCESS(RtlULongLongAdd(ullResult, bd, &ullResult)))
{
*pullResult = ullResult;
status = STATUS_SUCCESS;
}
}
}
}
}
}
if (!NT_SUCCESS(status))
{
*pullResult = ULONGLONG_ERROR;
}
#pragma warning(suppress:26071)
#endif // _USE_INTRINSIC_MULTIPLY128
return status;
}
View code on GitHub
No description available.