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