Skip to content

Commit 311f1ce

Browse files
committed
gh-129275: avoid temporary buffer in dec_as_long()
According to the documentation: "If rdata is non-NULL, it MUST be allocated by one of libmpdec’s allocation functions and rlen MUST be correct. If necessary, the function will resize rdata. Resizing is slow and should not occur if rlen has been obtained by a call to mpd_sizeinbase." So, possible resizing in mpd_qexport_u32/16() is for guarding against broken log10() implementations (log10 is used in the mpd_sizeinbase()).
1 parent bb5c687 commit 311f1ce

File tree

1 file changed

+17
-19
lines changed

1 file changed

+17
-19
lines changed

Modules/_decimal/_decimal.c

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3698,39 +3698,37 @@ dec_as_long(PyObject *dec, PyObject *context, int round)
36983698
assert(layout->digit_size == 2 || layout->digit_size == 4);
36993699

37003700
uint32_t base = (uint32_t)1 << layout->bits_per_digit;
3701-
/* We use a temporary buffer for digits for now, as for nonzero rdata
3702-
mpd_qexport_u32/u16() require either space "allocated by one of
3703-
libmpdec’s allocation functions" or "rlen MUST be correct" (to avoid
3704-
reallocation). This can be further optimized by using rlen from
3705-
mpd_sizeinbase(). See gh-127925. */
3706-
void *tmp_digits = NULL;
3707-
size_t n;
3701+
size_t n, len = mpd_sizeinbase(x, base);
3702+
void *digits;
3703+
PyLongWriter *writer = PyLongWriter_Create(mpd_isnegative(x), len, &digits);
3704+
3705+
if (writer == NULL) {
3706+
mpd_del(x);
3707+
return NULL;
3708+
}
37083709

37093710
status = 0;
3711+
/* The mpd_qexport_*() functions used here assume that no resizing occurs,
3712+
that is, 'len' was obtained via mpd_sizeinbase(). We also fill 'digits'
3713+
with zeros first since 'len' can be overestimated. */
37103714
if (layout->digit_size == 4) {
3711-
n = mpd_qexport_u32((uint32_t **)&tmp_digits, 0, base, x, &status);
3715+
memset(digits, 0, 4*len);
3716+
n = mpd_qexport_u32((uint32_t **)&digits, len, base, x, &status);
37123717
}
37133718
else {
3714-
n = mpd_qexport_u16((uint16_t **)&tmp_digits, 0, base, x, &status);
3719+
memset(digits, 0, 2*len);
3720+
n = mpd_qexport_u16((uint16_t **)&digits, len, base, x, &status);
37153721
}
37163722

37173723
if (n == SIZE_MAX) {
37183724
PyErr_NoMemory();
3725+
PyLongWriter_Discard(writer);
37193726
mpd_del(x);
3720-
mpd_free(tmp_digits);
37213727
return NULL;
37223728
}
37233729

3724-
void *digits;
3725-
PyLongWriter *writer = PyLongWriter_Create(mpd_isnegative(x), n, &digits);
3726-
3730+
assert(n <= len);
37273731
mpd_del(x);
3728-
if (writer == NULL) {
3729-
mpd_free(tmp_digits);
3730-
return NULL;
3731-
}
3732-
memcpy(digits, tmp_digits, layout->digit_size*n);
3733-
mpd_free(tmp_digits);
37343732
return PyLongWriter_Finish(writer);
37353733
}
37363734

0 commit comments

Comments
 (0)