Skip to content

Commit 9776b06

Browse files
authored
bpo-36262: Fix _Py_dg_strtod() memory leak (goto undfl) (GH-12276)
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.
1 parent 86900a4 commit 9776b06

File tree

2 files changed

+28
-54
lines changed

2 files changed

+28
-54
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 & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1441,8 +1441,9 @@ _Py_dg_strtod(const char *s00, char **se)
14411441
ULong y, z, abs_exp;
14421442
Long L;
14431443
BCinfo bc;
1444-
Bigint *bb, *bb1, *bd, *bd0, *bs, *delta;
1444+
Bigint *bb = NULL, *bd = NULL, *bd0 = NULL, *bs = NULL, *delta = NULL;
14451445
size_t ndigits, fraclen;
1446+
double result;
14461447

14471448
dval(&rv) = 0.;
14481449

@@ -1634,7 +1635,6 @@ _Py_dg_strtod(const char *s00, char **se)
16341635
if (k > 9) {
16351636
dval(&rv) = tens[k - 9] * dval(&rv) + z;
16361637
}
1637-
bd0 = 0;
16381638
if (nd <= DBL_DIG
16391639
&& Flt_Rounds == 1
16401640
) {
@@ -1804,14 +1804,11 @@ _Py_dg_strtod(const char *s00, char **se)
18041804

18051805
bd = Balloc(bd0->k);
18061806
if (bd == NULL) {
1807-
Bfree(bd0);
18081807
goto failed_malloc;
18091808
}
18101809
Bcopy(bd, bd0);
18111810
bb = sd2b(&rv, bc.scale, &bbe); /* srv = bb * 2^bbe */
18121811
if (bb == NULL) {
1813-
Bfree(bd);
1814-
Bfree(bd0);
18151812
goto failed_malloc;
18161813
}
18171814
/* Record whether lsb of bb is odd, in case we need this
@@ -1821,9 +1818,6 @@ _Py_dg_strtod(const char *s00, char **se)
18211818
/* tdv = bd * 10**e; srv = bb * 2**bbe */
18221819
bs = i2b(1);
18231820
if (bs == NULL) {
1824-
Bfree(bb);
1825-
Bfree(bd);
1826-
Bfree(bd0);
18271821
goto failed_malloc;
18281822
}
18291823

@@ -1874,54 +1868,36 @@ _Py_dg_strtod(const char *s00, char **se)
18741868
if (bb5 > 0) {
18751869
bs = pow5mult(bs, bb5);
18761870
if (bs == NULL) {
1877-
Bfree(bb);
1878-
Bfree(bd);
1879-
Bfree(bd0);
18801871
goto failed_malloc;
18811872
}
1882-
bb1 = mult(bs, bb);
1873+
Bigint *bb1 = mult(bs, bb);
18831874
Bfree(bb);
18841875
bb = bb1;
18851876
if (bb == NULL) {
1886-
Bfree(bs);
1887-
Bfree(bd);
1888-
Bfree(bd0);
18891877
goto failed_malloc;
18901878
}
18911879
}
18921880
if (bb2 > 0) {
18931881
bb = lshift(bb, bb2);
18941882
if (bb == NULL) {
1895-
Bfree(bs);
1896-
Bfree(bd);
1897-
Bfree(bd0);
18981883
goto failed_malloc;
18991884
}
19001885
}
19011886
if (bd5 > 0) {
19021887
bd = pow5mult(bd, bd5);
19031888
if (bd == NULL) {
1904-
Bfree(bb);
1905-
Bfree(bs);
1906-
Bfree(bd0);
19071889
goto failed_malloc;
19081890
}
19091891
}
19101892
if (bd2 > 0) {
19111893
bd = lshift(bd, bd2);
19121894
if (bd == NULL) {
1913-
Bfree(bb);
1914-
Bfree(bs);
1915-
Bfree(bd0);
19161895
goto failed_malloc;
19171896
}
19181897
}
19191898
if (bs2 > 0) {
19201899
bs = lshift(bs, bs2);
19211900
if (bs == NULL) {
1922-
Bfree(bb);
1923-
Bfree(bd);
1924-
Bfree(bd0);
19251901
goto failed_malloc;
19261902
}
19271903
}
@@ -1932,10 +1908,6 @@ _Py_dg_strtod(const char *s00, char **se)
19321908

19331909
delta = diff(bb, bd);
19341910
if (delta == NULL) {
1935-
Bfree(bb);
1936-
Bfree(bs);
1937-
Bfree(bd);
1938-
Bfree(bd0);
19391911
goto failed_malloc;
19401912
}
19411913
dsign = delta->sign;
@@ -1989,10 +1961,6 @@ _Py_dg_strtod(const char *s00, char **se)
19891961
}
19901962
delta = lshift(delta,Log2P);
19911963
if (delta == NULL) {
1992-
Bfree(bb);
1993-
Bfree(bs);
1994-
Bfree(bd);
1995-
Bfree(bd0);
19961964
goto failed_malloc;
19971965
}
19981966
if (cmp(delta, bs) > 0)
@@ -2094,11 +2062,6 @@ _Py_dg_strtod(const char *s00, char **se)
20942062
if ((word0(&rv) & Exp_mask) >=
20952063
Exp_msk1*(DBL_MAX_EXP+Bias-P)) {
20962064
if (word0(&rv0) == Big0 && word1(&rv0) == Big1) {
2097-
Bfree(bb);
2098-
Bfree(bd);
2099-
Bfree(bs);
2100-
Bfree(bd0);
2101-
Bfree(delta);
21022065
goto ovfl;
21032066
}
21042067
word0(&rv) = Big0;
@@ -2140,16 +2103,11 @@ _Py_dg_strtod(const char *s00, char **se)
21402103
}
21412104
}
21422105
cont:
2143-
Bfree(bb);
2144-
Bfree(bd);
2145-
Bfree(bs);
2146-
Bfree(delta);
2106+
Bfree(bb); bb = NULL;
2107+
Bfree(bd); bd = NULL;
2108+
Bfree(bs); bs = NULL;
2109+
Bfree(delta); delta = NULL;
21472110
}
2148-
Bfree(bb);
2149-
Bfree(bd);
2150-
Bfree(bs);
2151-
Bfree(bd0);
2152-
Bfree(delta);
21532111
if (bc.nd > nd) {
21542112
error = bigcomp(&rv, s0, &bc);
21552113
if (error)
@@ -2163,24 +2121,37 @@ _Py_dg_strtod(const char *s00, char **se)
21632121
}
21642122

21652123
ret:
2166-
return sign ? -dval(&rv) : dval(&rv);
2124+
result = sign ? -dval(&rv) : dval(&rv);
2125+
goto done;
21672126

21682127
parse_error:
2169-
return 0.0;
2128+
result = 0.0;
2129+
goto done;
21702130

21712131
failed_malloc:
21722132
errno = ENOMEM;
2173-
return -1.0;
2133+
result = -1.0;
2134+
goto done;
21742135

21752136
undfl:
2176-
return sign ? -0.0 : 0.0;
2137+
result = sign ? -0.0 : 0.0;
2138+
goto done;
21772139

21782140
ovfl:
21792141
errno = ERANGE;
21802142
/* Can't trust HUGE_VAL */
21812143
word0(&rv) = Exp_mask;
21822144
word1(&rv) = 0;
2183-
return sign ? -dval(&rv) : dval(&rv);
2145+
result = sign ? -dval(&rv) : dval(&rv);
2146+
goto done;
2147+
2148+
done:
2149+
Bfree(bb);
2150+
Bfree(bd);
2151+
Bfree(bs);
2152+
Bfree(bd0);
2153+
Bfree(delta);
2154+
return result;
21842155

21852156
}
21862157

0 commit comments

Comments
 (0)