Skip to content

Commit cea6cf8

Browse files
committed
py/formatfloat: Fix buffer overflow when formatting tiny numbers.
1 parent 0d1f886 commit cea6cf8

File tree

2 files changed

+26
-4
lines changed

2 files changed

+26
-4
lines changed

py/formatfloat.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "py/mpconfig.h"
2828
#if MICROPY_FLOAT_IMPL != MICROPY_FLOAT_IMPL_NONE
2929

30+
#include <assert.h>
3031
#include <stdlib.h>
3132
#include <stdint.h>
3233
#include "py/formatfloat.h"
@@ -210,13 +211,15 @@ int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, ch
210211
dec = -1;
211212
*s++ = first_dig;
212213

213-
if (prec + e + 1 > buf_remaining) {
214-
prec = buf_remaining - e - 1;
215-
}
216-
217214
if (org_fmt == 'g') {
218215
prec += (e - 1);
219216
}
217+
218+
// truncate precision to prevent buffer overflow
219+
if (prec + 2 > buf_remaining) {
220+
prec = buf_remaining - 2;
221+
}
222+
220223
num_digits = prec;
221224
if (num_digits) {
222225
*s++ = '.';
@@ -390,6 +393,9 @@ int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, ch
390393
}
391394
*s = '\0';
392395

396+
// verify that we did not overrun the input buffer
397+
assert((size_t)(s + 1 - buf) <= buf_size);
398+
393399
return s - buf;
394400
}
395401

tests/float/string_format_modulo.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,19 @@
2626
print("%+f %+f" % (1.23, -1.23)) # float sign
2727
print("% f % f" % (1.23, -1.23)) # float space sign
2828
print("%0f" % -1.23) # negative number with 0 padding
29+
30+
# numbers with large negative exponents
31+
print('%f' % 1e-10)
32+
print('%f' % 1e-20)
33+
print('%f' % 1e-50)
34+
print('%f' % 1e-100)
35+
print('%f' % 1e-300)
36+
37+
# large decimal precision should be truncated and not overflow buffer
38+
# the output depends on the FP calculation so only first 2 digits are printed
39+
# (the 'g' with small e are printed using 'f' style, so need to be checked)
40+
print(('%.40f' % 1e-300)[:2])
41+
print(('%.40g' % 1e-1)[:2])
42+
print(('%.40g' % 1e-2)[:2])
43+
print(('%.40g' % 1e-3)[:2])
44+
print(('%.40g' % 1e-4)[:2])

0 commit comments

Comments
 (0)