]> git.proxmox.com Git - mirror_edk2.git/commitdiff
MdePkg/BaseSafeIntLib: fix undefined behavior in SafeInt64Mult()
authorLaszlo Ersek <lersek@redhat.com>
Thu, 15 Feb 2018 16:09:43 +0000 (17:09 +0100)
committerLaszlo Ersek <lersek@redhat.com>
Wed, 21 Feb 2018 10:57:39 +0000 (11:57 +0100)
If we have to negate UnsignedResult (due to exactly one of Multiplicand
and Multiplier being negative), and UnsignedResult is exactly
MIN_INT64_MAGNITUDE (value 2^63), then the statement

        *Result = - ((INT64)UnsignedResult);

invokes both implementation-defined behavior and undefined behavior.

First, MIN_INT64_MAGNITUDE is not representable as INT64, therefore the
result of the (inner) conversion

  (INT64)MIN_INT64_MAGNITUDE

is implementation-defined, or an implementation-defined signal is raised,
according to ISO C99 6.3.1.3p3.

Second, if we assume that the C language implementation defines the
conversion to INT64 simply as reinterpreting the bit pattern
0x8000_0000_0000_0000 as a signed integer in two's complement
representation, then the conversion immediately produces the negative
value MIN_INT64 (value -(2^63)). In turn, the (outer) negation

  -(MIN_INT64)

invokes undefined behavior, because the mathematical result of the
negation, namely 2^63, cannot be represented in an INT64 object. (Not even
mentioning the fact that the mathematical result would be incorrect.) In
practice, the undefined negation of MIN_INT64 happens to produce an
unchanged, valid-looking result on x86, i.e. (-(MIN_INT64)) == MIN_INT64.

We can summarize this as the undefined -- effectless -- negation canceling
out the botched -- auto-negating -- implementation-defined conversion.
Instead of relying on such behavior, dedicate a branch to this situation:
assign MIN_INT64 directly. The branch can be triggered e.g. by multiplying
(2^62) by (-2).

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>
MdePkg/Library/BaseSafeIntLib/SafeIntLib.c

index de91ffeca2a560b17b0bbc8cd7dd6309b745c9e3..c5f13d7e08285f46f3cf5bcd66afeb7cb593ca38 100644 (file)
@@ -4143,6 +4143,8 @@ SafeInt64Mult (
       if (UnsignedResult > MIN_INT64_MAGNITUDE) {\r
         *Result = INT64_ERROR;\r
         Status = RETURN_BUFFER_TOO_SMALL;\r
+      } else if (UnsignedResult == MIN_INT64_MAGNITUDE) {\r
+        *Result = MIN_INT64;\r
       } else {\r
         *Result = - ((INT64)UnsignedResult);\r
       }\r