Skip to content

Commit b140578

Browse files
authored
bpo-36262: Fix _Py_dg_strtod() memory leak (goto undfl) (GH-12276) (GH-12332)
Fix an unlikely memory leak on conversion from string to float in the function _Py_dg_strtod() used by float(str), complex(str), pickle.load(), marshal.load(), etc. Fix an unlikely memory leak in _Py_dg_strtod() on "undfl:" label: rewrite memory management in this function to always release all memory before exiting the function. Initialize variables to NULL, and set them to NULL after calling Bfree() at the "cont:" label. Note: Bfree(NULL) is well defined: it does nothing. (cherry picked from commit 9776b06)
1 parent 2dd6e07 commit b140578

File tree

2 files changed

+28
-53
lines changed

2 files changed

+28
-53
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix an unlikely memory leak on conversion from string to float in the function
2+
``_Py_dg_strtod()`` used by ``float(str)``, ``complex(str)``,
3+
:func:`pickle.load`, :func:`marshal.load`, etc.

Python/dtoa.c

Lines changed: 25 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1514,8 +1514,9 @@ _Py_dg_strtod(const char *s00, char **se)
15141514
ULong y, z, abs_exp;
15151515
Long L;
15161516
BCinfo bc;
1517-
Bigint *bb, *bb1, *bd, *bd0, *bs, *delta;
1517+
Bigint *bb = NULL, *bd = NULL, *bd0 = NULL, *bs = NULL, *delta = NULL;
15181518
size_t ndigits, fraclen;
1519+
double result;
15191520

15201521
dval(&rv) = 0.;
15211522

@@ -1707,7 +1708,6 @@ _Py_dg_strtod(const char *s00, char **se)
17071708
if (k > 9) {
17081709
dval(&rv) = tens[k - 9] * dval(&rv) + z;
17091710
}
1710-
bd0 = 0;
17111711
if (nd <= DBL_DIG
17121712
&& Flt_Rounds == 1
17131713
) {
@@ -1877,14 +1877,11 @@ _Py_dg_strtod(const char *s00, char **se)
18771877

18781878
bd = Balloc(bd0->k);
18791879
if (bd == NULL) {
1880-
Bfree(bd0);
18811880
goto failed_malloc;
18821881
}
18831882
Bcopy(bd, bd0);
18841883
bb = sd2b(&rv, bc.scale, &bbe); /* srv = bb * 2^bbe */
18851884
if (bb == NULL) {
1886-
Bfree(bd);
1887-
Bfree(bd0);
18881885
goto failed_malloc;
18891886
}
18901887
/* Record whether lsb of bb is odd, in case we need this
@@ -1894,9 +1891,6 @@ _Py_dg_strtod(const char *s00, char **se)
18941891
/* tdv = bd * 10**e; srv = bb * 2**bbe */
18951892
bs = i2b(1);
18961893
if (bs == NULL) {
1897-
Bfree(bb);
1898-
Bfree(bd);
1899-
Bfree(bd0);
19001894
goto failed_malloc;
19011895
}
19021896

@@ -1945,56 +1939,39 @@ _Py_dg_strtod(const char *s00, char **se)
19451939

19461940
/* Scale bb, bd, bs by the appropriate powers of 2 and 5. */
19471941
if (bb5 > 0) {
1942+
Bigint *bb1;
19481943
bs = pow5mult(bs, bb5);
19491944
if (bs == NULL) {
1950-
Bfree(bb);
1951-
Bfree(bd);
1952-
Bfree(bd0);
19531945
goto failed_malloc;
19541946
}
19551947
bb1 = mult(bs, bb);
19561948
Bfree(bb);
19571949
bb = bb1;
19581950
if (bb == NULL) {
1959-
Bfree(bs);
1960-
Bfree(bd);
1961-
Bfree(bd0);
19621951
goto failed_malloc;
19631952
}
19641953
}
19651954
if (bb2 > 0) {
19661955
bb = lshift(bb, bb2);
19671956
if (bb == NULL) {
1968-
Bfree(bs);
1969-
Bfree(bd);
1970-
Bfree(bd0);
19711957
goto failed_malloc;
19721958
}
19731959
}
19741960
if (bd5 > 0) {
19751961
bd = pow5mult(bd, bd5);
19761962
if (bd == NULL) {
1977-
Bfree(bb);
1978-
Bfree(bs);
1979-
Bfree(bd0);
19801963
goto failed_malloc;
19811964
}
19821965
}
19831966
if (bd2 > 0) {
19841967
bd = lshift(bd, bd2);
19851968
if (bd == NULL) {
1986-
Bfree(bb);
1987-
Bfree(bs);
1988-
Bfree(bd0);
19891969
goto failed_malloc;
19901970
}
19911971
}
19921972
if (bs2 > 0) {
19931973
bs = lshift(bs, bs2);
19941974
if (bs == NULL) {
1995-
Bfree(bb);
1996-
Bfree(bd);
1997-
Bfree(bd0);
19981975
goto failed_malloc;
19991976
}
20001977
}
@@ -2005,10 +1982,6 @@ _Py_dg_strtod(const char *s00, char **se)
20051982

20061983
delta = diff(bb, bd);
20071984
if (delta == NULL) {
2008-
Bfree(bb);
2009-
Bfree(bs);
2010-
Bfree(bd);
2011-
Bfree(bd0);
20121985
goto failed_malloc;
20131986
}
20141987
dsign = delta->sign;
@@ -2062,10 +2035,6 @@ _Py_dg_strtod(const char *s00, char **se)
20622035
}
20632036
delta = lshift(delta,Log2P);
20642037
if (delta == NULL) {
2065-
Bfree(bb);
2066-
Bfree(bs);
2067-
Bfree(bd);
2068-
Bfree(bd0);
20692038
goto failed_malloc;
20702039
}
20712040
if (cmp(delta, bs) > 0)
@@ -2167,11 +2136,6 @@ _Py_dg_strtod(const char *s00, char **se)
21672136
if ((word0(&rv) & Exp_mask) >=
21682137
Exp_msk1*(DBL_MAX_EXP+Bias-P)) {
21692138
if (word0(&rv0) == Big0 && word1(&rv0) == Big1) {
2170-
Bfree(bb);
2171-
Bfree(bd);
2172-
Bfree(bs);
2173-
Bfree(bd0);
2174-
Bfree(delta);
21752139
goto ovfl;
21762140
}
21772141
word0(&rv) = Big0;
@@ -2213,16 +2177,11 @@ _Py_dg_strtod(const char *s00, char **se)
22132177
}
22142178
}
22152179
cont:
2216-
Bfree(bb);
2217-
Bfree(bd);
2218-
Bfree(bs);
2219-
Bfree(delta);
2180+
Bfree(bb); bb = NULL;
2181+
Bfree(bd); bd = NULL;
2182+
Bfree(bs); bs = NULL;
2183+
Bfree(delta); delta = NULL;
22202184
}
2221-
Bfree(bb);
2222-
Bfree(bd);
2223-
Bfree(bs);
2224-
Bfree(bd0);
2225-
Bfree(delta);
22262185
if (bc.nd > nd) {
22272186
error = bigcomp(&rv, s0, &bc);
22282187
if (error)
@@ -2236,24 +2195,37 @@ _Py_dg_strtod(const char *s00, char **se)
22362195
}
22372196

22382197
ret:
2239-
return sign ? -dval(&rv) : dval(&rv);
2198+
result = sign ? -dval(&rv) : dval(&rv);
2199+
goto done;
22402200

22412201
parse_error:
2242-
return 0.0;
2202+
result = 0.0;
2203+
goto done;
22432204

22442205
failed_malloc:
22452206
errno = ENOMEM;
2246-
return -1.0;
2207+
result = -1.0;
2208+
goto done;
22472209

22482210
undfl:
2249-
return sign ? -0.0 : 0.0;
2211+
result = sign ? -0.0 : 0.0;
2212+
goto done;
22502213

22512214
ovfl:
22522215
errno = ERANGE;
22532216
/* Can't trust HUGE_VAL */
22542217
word0(&rv) = Exp_mask;
22552218
word1(&rv) = 0;
2256-
return sign ? -dval(&rv) : dval(&rv);
2219+
result = sign ? -dval(&rv) : dval(&rv);
2220+
goto done;
2221+
2222+
done:
2223+
Bfree(bb);
2224+
Bfree(bd);
2225+
Bfree(bs);
2226+
Bfree(bd0);
2227+
Bfree(delta);
2228+
return result;
22572229

22582230
}
22592231

0 commit comments

Comments
 (0)