Piotr Caban : msvcrt: Create 64-bit mantissa in fpnum_parse.

Alexandre Julliard julliard at winehq.org
Thu Jul 23 16:36:57 CDT 2020


Module: wine
Branch: master
Commit: 8fc48e8bc2507ae8123c749a09c0be60a26e397d
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=8fc48e8bc2507ae8123c749a09c0be60a26e397d

Author: Piotr Caban <piotr at codeweavers.com>
Date:   Thu Jul 23 15:38:34 2020 +0200

msvcrt: Create 64-bit mantissa in fpnum_parse.

Signed-off-by: Piotr Caban <piotr at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/msvcrt/bnum.h   | 11 ++---------
 dlls/msvcrt/string.c | 31 ++++++++++++++++++++++++++-----
 2 files changed, 28 insertions(+), 14 deletions(-)

diff --git a/dlls/msvcrt/bnum.h b/dlls/msvcrt/bnum.h
index 5cc71c1e68..144db353fe 100644
--- a/dlls/msvcrt/bnum.h
+++ b/dlls/msvcrt/bnum.h
@@ -28,7 +28,8 @@ static const int p10s[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
 #define LIMB_MAX 1000000000     /* 10^9 */
 
 #define BNUM_PREC64 128         /* data size needed to store 64-bit double */
-/* bnum represents real number with fixed decimal point (after 2 limbs) */
+
+/* bnum represents real number with fixed decimal point */
 struct bnum {
     int b; /* least significant digit position */
     int e; /* most significant digit position + 1 */
@@ -41,14 +42,6 @@ static inline int bnum_idx(struct bnum *b, int idx)
     return idx & (b->size - 1);
 }
 
-/* Returns integral part of bnum */
-static inline ULONGLONG bnum_to_mant(struct bnum *b)
-{
-    ULONGLONG ret = (ULONGLONG)b->data[bnum_idx(b, b->e-1)] * LIMB_MAX;
-    if(b->b != b->e-1) ret += b->data[bnum_idx(b, b->e-2)];
-    return ret;
-}
-
 /* Returns TRUE if new most significant limb was added */
 static inline BOOL bnum_lshift(struct bnum *b, int shift)
 {
diff --git a/dlls/msvcrt/string.c b/dlls/msvcrt/string.c
index 5732d511fd..a2ec9a91ac 100644
--- a/dlls/msvcrt/string.c
+++ b/dlls/msvcrt/string.c
@@ -597,6 +597,21 @@ static struct fpnum fpnum_parse16(MSVCRT_wchar_t get(void *ctx), void unget(void
 }
 #endif
 
+/* Converts first 3 limbs to ULONGLONG */
+/* Return FALSE on overflow */
+static inline BOOL bnum_to_mant(struct bnum *b, ULONGLONG *m)
+{
+    if(MSVCRT_UI64_MAX / LIMB_MAX / LIMB_MAX < b->data[bnum_idx(b, b->e-1)]) return FALSE;
+    *m = (ULONGLONG)b->data[bnum_idx(b, b->e-1)] * LIMB_MAX * LIMB_MAX;
+    if(b->b == b->e-1) return TRUE;
+    if(MSVCRT_UI64_MAX - *m < (ULONGLONG)b->data[bnum_idx(b, b->e-2)] * LIMB_MAX) return FALSE;
+    *m += (ULONGLONG)b->data[bnum_idx(b, b->e-2)] * LIMB_MAX;
+    if(b->b == b->e-2) return TRUE;
+    if(MSVCRT_UI64_MAX - *m < b->data[bnum_idx(b, b->e-3)]) return FALSE;
+    *m += b->data[bnum_idx(b, b->e-3)];
+    return TRUE;
+}
+
 struct fpnum fpnum_parse(MSVCRT_wchar_t (*get)(void *ctx), void (*unget)(void *ctx),
         void *ctx, MSVCRT_pthreadlocinfo locinfo)
 {
@@ -612,6 +627,7 @@ struct fpnum fpnum_parse(MSVCRT_wchar_t (*get)(void *ctx), void (*unget)(void *c
     struct bnum *b = (struct bnum*)bnum_data;
     enum fpmod round = FP_ROUND_ZERO;
     MSVCRT_wchar_t nch;
+    ULONGLONG m;
 
     nch = get(ctx);
     if(nch == '-') {
@@ -797,28 +813,33 @@ struct fpnum fpnum_parse(MSVCRT_wchar_t (*get)(void *ctx), void (*unget)(void *c
     if(dp-1 < MSVCRT_DBL_MIN_10_EXP-MSVCRT_DBL_DIG-18)
         return fpnum(sign, INT_MIN, 1, FP_ROUND_ZERO);
 
-    while(dp > 2*LIMB_DIGITS) {
+    while(dp > 3*LIMB_DIGITS) {
         if(bnum_rshift(b, 9)) dp -= LIMB_DIGITS;
         e2 += 9;
     }
-    while(dp <= LIMB_DIGITS) {
+    while(dp <= 2*LIMB_DIGITS) {
         if(bnum_lshift(b, 29)) dp += LIMB_DIGITS;
         e2 -= 29;
     }
-    while(b->data[bnum_idx(b, b->e-1)] < LIMB_MAX/10) {
+    /* Make sure most significant mantissa bit will be set */
+    while(b->data[bnum_idx(b, b->e-1)] <= 9) {
         bnum_lshift(b, 1);
         e2--;
     }
+    while(!bnum_to_mant(b, &m)) {
+        bnum_rshift(b, 1);
+        e2++;
+    }
 
     /* Check if fractional part is non-zero */
     /* Caution: it's only correct because bnum_to_mant returns more than 53 bits */
-    for(i=b->e-3; i>=b->b; i--) {
+    for(i=b->e-4; i>=b->b; i--) {
         if (!b->data[bnum_idx(b, b->b)]) continue;
         round = FP_ROUND_DOWN;
         break;
     }
 
-    return fpnum(sign, e2, bnum_to_mant(b), round);
+    return fpnum(sign, e2, m, round);
 }
 
 static MSVCRT_wchar_t strtod_str_get(void *ctx)




More information about the wine-cvs mailing list