+44
-1
lines changedFilter options
+44
-1
lines changed Original file line number Diff line number Diff line change
@@ -30,7 +30,20 @@ def format(number, decimal_sep, decimal_pos=None, grouping=0, thousand_sep='',
30
30
# sign
31
31
sign = ''
32
32
if isinstance(number, Decimal):
33
-
str_number = '{:f}'.format(number)
33
+
# Format values with more than 200 digits (an arbitrary cutoff) using
34
+
# scientific notation to avoid high memory usage in {:f}'.format().
35
+
_, digits, exponent = number.as_tuple()
36
+
if abs(exponent) + len(digits) > 200:
37
+
number = '{:e}'.format(number)
38
+
coefficient, exponent = number.split('e')
39
+
# Format the coefficient.
40
+
coefficient = format(
41
+
coefficient, decimal_sep, decimal_pos, grouping,
42
+
thousand_sep, force_grouping,
43
+
)
44
+
return '{}e{}'.format(coefficient, exponent)
45
+
else:
46
+
str_number = '{:f}'.format(number)
34
47
else:
35
48
str_number = six.text_type(number)
36
49
if str_number[0] == '-':
Original file line number Diff line number Diff line change
@@ -5,3 +5,15 @@ Django 1.11.19 release notes
5
5
*February 11, 2019*
6
6
7
7
Django 1.11.19 fixes a security issue in 1.11.18.
8
+
9
+
CVE-2019-6975: Memory exhaustion in ``django.utils.numberformat.format()``
10
+
--------------------------------------------------------------------------
11
+
12
+
If ``django.utils.numberformat.format()`` -- used by ``contrib.admin`` as well
13
+
as the the ``floatformat``, ``filesizeformat``, and ``intcomma`` templates
14
+
filters -- received a ``Decimal`` with a large number of digits or a large
15
+
exponent, it could lead to significant memory usage due to a call to
16
+
``'{:f}'.format()``.
17
+
18
+
To avoid this, decimals with more than 200 digits are now formatted using
19
+
scientific notation.
Original file line number Diff line number Diff line change
@@ -60,6 +60,24 @@ def test_decimal_numbers(self):
60
60
self.assertEqual(nformat(Decimal('1234'), '.', grouping=2, thousand_sep=',', force_grouping=True), '12,34')
61
61
self.assertEqual(nformat(Decimal('-1234.33'), '.', decimal_pos=1), '-1234.3')
62
62
self.assertEqual(nformat(Decimal('0.00000001'), '.', decimal_pos=8), '0.00000001')
63
+
# Very large & small numbers.
64
+
tests = [
65
+
('9e9999', None, '9e+9999'),
66
+
('9e9999', 3, '9.000e+9999'),
67
+
('9e201', None, '9e+201'),
68
+
('9e200', None, '9e+200'),
69
+
('1.2345e999', 2, '1.23e+999'),
70
+
('9e-999', None, '9e-999'),
71
+
('1e-7', 8, '0.00000010'),
72
+
('1e-8', 8, '0.00000001'),
73
+
('1e-9', 8, '0.00000000'),
74
+
('1e-10', 8, '0.00000000'),
75
+
('1e-11', 8, '0.00000000'),
76
+
('1' + ('0' * 300), 3, '1.000e+300'),
77
+
('0.{}1234'.format('0' * 299), 3, '1.234e-300'),
78
+
]
79
+
for value, decimal_pos, expected_value in tests:
80
+
self.assertEqual(nformat(Decimal(value), '.', decimal_pos), expected_value)
63
81
64
82
def test_decimal_subclass(self):
65
83
class EuroDecimal(Decimal):
You can’t perform that action at this time.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4