mirror of https://github.com/acidanthera/audk.git
MdePkg/BaseSafeIntLib: fix undefined behavior in SafeInt64Add()
The addition in the assignment SignedResult = Augend + Addend; is performed with unchecked INT64 operands. According to ISO C, if the mathematical result of signed integer addition cannot be represented in the result type, the behavior is undefined. (Refer to ISO C99 6.5p5. 6.2.5p9 only exempts unsigned integers, and 6.3.1.3p3 does not apply because it treats the conversion of integers that have been successfully evaluated first.) Replace the after-the-fact result checking with checks on the operands, and only perform the addition if it is safe. Cc: Bret Barkelew <Bret.Barkelew@microsoft.com> Cc: Liming Gao <liming.gao@intel.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Cc: Sean Brogan <sean.brogan@microsoft.com> Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Laszlo Ersek <lersek@redhat.com> Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Tested-by: Michael D Kinney <michael.d.kinney@intel.com>
This commit is contained in:
parent
54c7728a04
commit
41bfaffd13
|
@ -3631,26 +3631,62 @@ SafeInt64Add (
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
RETURN_STATUS Status;
|
RETURN_STATUS Status;
|
||||||
INT64 SignedResult;
|
|
||||||
|
|
||||||
if (Result == NULL) {
|
if (Result == NULL) {
|
||||||
return RETURN_INVALID_PARAMETER;
|
return RETURN_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
SignedResult = Augend + Addend;
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Adding positive to negative never overflows.
|
// * An Addend of zero can never cause underflow or overflow.
|
||||||
// If you add two positive numbers, you expect a positive result.
|
|
||||||
// If you add two negative numbers, you expect a negative result.
|
|
||||||
// Overflow if inputs are the same sign and output is not that sign.
|
|
||||||
//
|
//
|
||||||
if (((Augend < 0) == (Addend < 0)) &&
|
// * A positive Addend can only cause overflow. The overflow condition is
|
||||||
((Augend < 0) != (SignedResult < 0))) {
|
//
|
||||||
|
// (Augend + Addend) > MAX_INT64
|
||||||
|
//
|
||||||
|
// Subtracting Addend from both sides yields
|
||||||
|
//
|
||||||
|
// Augend > (MAX_INT64 - Addend)
|
||||||
|
//
|
||||||
|
// This condition can be coded directly in C because the RHS will neither
|
||||||
|
// underflow nor overflow. That is due to the starting condition:
|
||||||
|
//
|
||||||
|
// 0 < Addend <= MAX_INT64
|
||||||
|
//
|
||||||
|
// Multiplying all three sides by (-1) yields
|
||||||
|
//
|
||||||
|
// 0 > (-Addend) >= (-MAX_INT64)
|
||||||
|
//
|
||||||
|
// Adding MAX_INT64 to all three sides yields
|
||||||
|
//
|
||||||
|
// MAX_INT64 > (MAX_INT64 - Addend) >= 0
|
||||||
|
//
|
||||||
|
// * A negative Addend can only cause underflow. The underflow condition is
|
||||||
|
//
|
||||||
|
// (Augend + Addend) < MIN_INT64
|
||||||
|
//
|
||||||
|
// Subtracting Addend from both sides yields
|
||||||
|
//
|
||||||
|
// Augend < (MIN_INT64 - Addend)
|
||||||
|
//
|
||||||
|
// This condition can be coded directly in C because the RHS will neither
|
||||||
|
// underflow nor overflow. That is due to the starting condition:
|
||||||
|
//
|
||||||
|
// MIN_INT64 <= Addend < 0
|
||||||
|
//
|
||||||
|
// Multiplying all three sides by (-1) yields
|
||||||
|
//
|
||||||
|
// (-MIN_INT64) >= (-Addend) > 0
|
||||||
|
//
|
||||||
|
// Adding MIN_INT64 to all three sides yields
|
||||||
|
//
|
||||||
|
// 0 >= (MIN_INT64 - Addend) > MIN_INT64
|
||||||
|
//
|
||||||
|
if (((Addend > 0) && (Augend > (MAX_INT64 - Addend))) ||
|
||||||
|
((Addend < 0) && (Augend < (MIN_INT64 - Addend)))) {
|
||||||
*Result = INT64_ERROR;
|
*Result = INT64_ERROR;
|
||||||
Status = RETURN_BUFFER_TOO_SMALL;
|
Status = RETURN_BUFFER_TOO_SMALL;
|
||||||
} else {
|
} else {
|
||||||
*Result = SignedResult;
|
*Result = Augend + Addend;
|
||||||
Status = RETURN_SUCCESS;
|
Status = RETURN_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue