[PATCH] msvcp120: Fix _Xtime_diff_to_millis2 overflow behavior.

Stefan Dösinger stefan at codeweavers.com
Wed Oct 11 10:07:39 CDT 2017


This fixes freezes during game installation in Wargaming.net Game
Center.

Signed-off-by: Stefan Dösinger <stefan at codeweavers.com>

---

I suspect native doesn't have a check like I am using because it would
require deliberate effort to allow overflows to happen. I suspect they
are simply using a 128 bit integer. Is there a portable way of doing so?
---
 dlls/msvcp120/tests/msvcp120.c | 22 +++++++++++++++++++++-
 dlls/msvcp90/misc.c            | 10 ++++++++--
 2 files changed, 29 insertions(+), 3 deletions(-)

diff --git a/dlls/msvcp120/tests/msvcp120.c b/dlls/msvcp120/tests/msvcp120.c
index cd7d45719f..bfd0300549 100644
--- a/dlls/msvcp120/tests/msvcp120.c
+++ b/dlls/msvcp120/tests/msvcp120.c
@@ -570,6 +570,15 @@ static void test__Xtime_diff_to_millis2(void)
         {0, 0, 0, 1234000001, 1235},
         {0, 0, 0, 1234000009, 1235},
         {0, 0, -1, 0, 0},
+        {1, 0, 0, 0, 0},
+        {0, 1000000000, 0, 0, 0},
+        {0x7FFFFFFF / 1000, 0, 0, 0, 0},
+        {2147484, 0, 0, 0, 0}, /* ceil(0x80000000 / 1000) */
+        {2147485, 0, 0, 0, 0}, /* ceil(0x80000000 / 1000) + 1*/
+        {0, 0, 0x7FFFFFFF / 1000, 0, 2147483000},
+        {0, 0, 0x7FFFFFFF / 1000, 647000000, 0x7FFFFFFF}, /* max */
+        {0, 0, 0x7FFFFFFF / 1000, 647000001, -2147483648}, /* overflow. */
+        {0, 0, 2147484, 0, -2147483296}, /* ceil(0x80000000 / 1000), overflow*/
         {0, 0, 0, -10000000, 0},
         {0, 0, -1, -100000000, 0},
         {-1, 0, 0, 0, 1000},
@@ -577,7 +586,18 @@ static void test__Xtime_diff_to_millis2(void)
         {-1, -100000000, 0, 0, 1100},
         {0, 0, -1, 2000000000, 1000},
         {0, 0, -2, 2000000000, 0},
-        {0, 0, -2, 2100000000, 100}
+        {0, 0, -2, 2100000000, 100},
+        {0, 0, 0x7FFFFFFFFFFFFFFF / 1000, 0, -808}, /* Still fits in a signed 64 bit number */
+        {0, 0, 0x7FFFFFFFFFFFFFFF / 1000, 1000000000, 192}, /* Overflows a signed 64 bit number */
+        {0, 0, 0x8000000000001000 / 1000, 1000000000, 4192}, /* Overflows a signed 64 bit number */
+        {0x7FFFFFFFFFFFFFFD, 0, 0x7FFFFFFFFFFFFFFF, 0, 2000}, /* Not an overflow */
+        {0x7FFFFFFFFFFFFFFF, 0, 0x7FFFFFFFFFFFFFFD, 0, 0}, /* Not an overflow */
+
+        /* October 11th 2017, 12:34:59 UTC */
+        {1507725144, 983274000, 0, 0, 0},
+        {0, 0, 1507725144, 983274000, 191624088},
+        {1507725144, 983274000, 1507725145, 983274000, 1000},
+        {1507725145, 983274000, 1507725145, 983274000, 0},
     };
     int i;
     MSVCRT_long ret;
diff --git a/dlls/msvcp90/misc.c b/dlls/msvcp90/misc.c
index 28d1af3c79..0f57557ffc 100644
--- a/dlls/msvcp90/misc.c
+++ b/dlls/msvcp90/misc.c
@@ -402,7 +402,7 @@ int __cdecl xtime_get(xtime* t, int unknown)
 MSVCRT_long __cdecl _Xtime_diff_to_millis2(const xtime *t1, const xtime *t2)
 {
     __time64_t diff_sec;
-    MSVCRT_long diff_nsec, ret;
+    LONGLONG diff_nsec, ret;
 
     TRACE("(%p, %p)\n", t1, t2);
 
@@ -410,7 +410,13 @@ MSVCRT_long __cdecl _Xtime_diff_to_millis2(const xtime *t1, const xtime *t2)
     diff_nsec = t1->nsec - t2->nsec;
     ret = diff_sec * MILLISEC_PER_SEC +
             (diff_nsec + NANOSEC_PER_MILLISEC - 1) / NANOSEC_PER_MILLISEC;
-    return ret > 0 ? ret : 0;
+
+    /* This function does not return negative numbers, except when they get created through
+     * an integer overflow. */
+    if (diff_sec > ((LONGLONG)INT_MAX + NANOSEC_PER_MILLISEC - 1) / NANOSEC_PER_MILLISEC)
+        return ret;
+    else
+        return ret > 0 ? ret : 0;
 }
 
 /* _Xtime_diff_to_millis */
-- 
2.13.6




More information about the wine-patches mailing list