gh-95504: Fix negative numbers in PyUnicode_FromFormat (GH-95848)

Co-authored-by: philg314 <110174000+philg314@users.noreply.github.com>
This commit is contained in:
Petr Viktorin 2022-08-10 13:12:40 +02:00 committed by GitHub
parent cf28540fd3
commit 71c3d649b5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 86 additions and 7 deletions

View file

@ -475,6 +475,9 @@ Porting to Python 3.12
copied as-is to the result string, and any extra arguments discarded. copied as-is to the result string, and any extra arguments discarded.
(Contributed by Serhiy Storchaka in :gh:`95781`.) (Contributed by Serhiy Storchaka in :gh:`95781`.)
* Fixed wrong sign placement in :c:func:`PyUnicode_FromFormat` and
:c:func:`PyUnicode_FromFormatV`.
(Contributed by Philip Georgi in :gh:`95504`.)
Deprecated Deprecated
---------- ----------

View file

@ -608,8 +608,8 @@ Marius Gedminas
Jan-Philip Gehrcke Jan-Philip Gehrcke
Thomas Gellekum Thomas Gellekum
Gabriel Genellina Gabriel Genellina
Christos Georgiou
Philip Georgi Philip Georgi
Christos Georgiou
Elazar (אלעזר) Gershuni Elazar (אלעזר) Gershuni
Ben Gertzfield Ben Gertzfield
Nadim Ghaznavi Nadim Ghaznavi

View file

@ -0,0 +1,3 @@
Fix sign placement when specifying width or precision in
:c:func:`PyUnicode_FromFormat` and :c:func:`PyUnicode_FromFormatV`.
Patch by Philip Georgi.

View file

@ -433,6 +433,16 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored))
CHECK_FORMAT_1("%05zu", "00123", (size_t)123); CHECK_FORMAT_1("%05zu", "00123", (size_t)123);
CHECK_FORMAT_1("%05x", "0007b", (int)123); CHECK_FORMAT_1("%05x", "0007b", (int)123);
CHECK_FORMAT_1("%05d", "-0123", (int)-123);
CHECK_FORMAT_1("%05i", "-0123", (int)-123);
CHECK_FORMAT_1("%05ld", "-0123", (long)-123);
CHECK_FORMAT_1("%05li", "-0123", (long)-123);
CHECK_FORMAT_1("%05lld", "-0123", (long long)-123);
CHECK_FORMAT_1("%05lli", "-0123", (long long)-123);
CHECK_FORMAT_1("%05zd", "-0123", (Py_ssize_t)-123);
CHECK_FORMAT_1("%05zi", "-0123", (Py_ssize_t)-123);
CHECK_FORMAT_1("%09x", "0ffffff85", (int)-123);
// Integers: precision < length // Integers: precision < length
CHECK_FORMAT_1("%.1d", "123", (int)123); CHECK_FORMAT_1("%.1d", "123", (int)123);
CHECK_FORMAT_1("%.1i", "123", (int)123); CHECK_FORMAT_1("%.1i", "123", (int)123);
@ -473,6 +483,16 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored))
CHECK_FORMAT_1("%.5zu", "00123", (size_t)123); CHECK_FORMAT_1("%.5zu", "00123", (size_t)123);
CHECK_FORMAT_1("%.5x", "0007b", (int)123); CHECK_FORMAT_1("%.5x", "0007b", (int)123);
CHECK_FORMAT_1("%.5d", "-00123", (int)-123);
CHECK_FORMAT_1("%.5i", "-00123", (int)-123);
CHECK_FORMAT_1("%.5ld", "-00123", (long)-123);
CHECK_FORMAT_1("%.5li", "-00123", (long)-123);
CHECK_FORMAT_1("%.5lld", "-00123", (long long)-123);
CHECK_FORMAT_1("%.5lli", "-00123", (long long)-123);
CHECK_FORMAT_1("%.5zd", "-00123", (Py_ssize_t)-123);
CHECK_FORMAT_1("%.5zi", "-00123", (Py_ssize_t)-123);
CHECK_FORMAT_1("%.9x", "0ffffff85", (int)-123);
// Integers: width > precision > length // Integers: width > precision > length
CHECK_FORMAT_1("%7.5d", " 00123", (int)123); CHECK_FORMAT_1("%7.5d", " 00123", (int)123);
CHECK_FORMAT_1("%7.5i", " 00123", (int)123); CHECK_FORMAT_1("%7.5i", " 00123", (int)123);
@ -488,6 +508,16 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored))
CHECK_FORMAT_1("%7.5zu", " 00123", (size_t)123); CHECK_FORMAT_1("%7.5zu", " 00123", (size_t)123);
CHECK_FORMAT_1("%7.5x", " 0007b", (int)123); CHECK_FORMAT_1("%7.5x", " 0007b", (int)123);
CHECK_FORMAT_1("%7.5d", " -00123", (int)-123);
CHECK_FORMAT_1("%7.5i", " -00123", (int)-123);
CHECK_FORMAT_1("%7.5ld", " -00123", (long)-123);
CHECK_FORMAT_1("%7.5li", " -00123", (long)-123);
CHECK_FORMAT_1("%7.5lld", " -00123", (long long)-123);
CHECK_FORMAT_1("%7.5lli", " -00123", (long long)-123);
CHECK_FORMAT_1("%7.5zd", " -00123", (Py_ssize_t)-123);
CHECK_FORMAT_1("%7.5zi", " -00123", (Py_ssize_t)-123);
CHECK_FORMAT_1("%10.9x", " 0ffffff85", (int)-123);
// Integers: width > precision > length, 0-flag // Integers: width > precision > length, 0-flag
CHECK_FORMAT_1("%07.5d", "0000123", (int)123); CHECK_FORMAT_1("%07.5d", "0000123", (int)123);
CHECK_FORMAT_1("%07.5i", "0000123", (int)123); CHECK_FORMAT_1("%07.5i", "0000123", (int)123);
@ -503,6 +533,16 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored))
CHECK_FORMAT_1("%07.5zu", "0000123", (size_t)123); CHECK_FORMAT_1("%07.5zu", "0000123", (size_t)123);
CHECK_FORMAT_1("%07.5x", "000007b", (int)123); CHECK_FORMAT_1("%07.5x", "000007b", (int)123);
CHECK_FORMAT_1("%07.5d", "-000123", (int)-123);
CHECK_FORMAT_1("%07.5i", "-000123", (int)-123);
CHECK_FORMAT_1("%07.5ld", "-000123", (long)-123);
CHECK_FORMAT_1("%07.5li", "-000123", (long)-123);
CHECK_FORMAT_1("%07.5lld", "-000123", (long long)-123);
CHECK_FORMAT_1("%07.5lli", "-000123", (long long)-123);
CHECK_FORMAT_1("%07.5zd", "-000123", (Py_ssize_t)-123);
CHECK_FORMAT_1("%07.5zi", "-000123", (Py_ssize_t)-123);
CHECK_FORMAT_1("%010.9x", "00ffffff85", (int)-123);
// Integers: precision > width > length // Integers: precision > width > length
CHECK_FORMAT_1("%5.7d", "0000123", (int)123); CHECK_FORMAT_1("%5.7d", "0000123", (int)123);
CHECK_FORMAT_1("%5.7i", "0000123", (int)123); CHECK_FORMAT_1("%5.7i", "0000123", (int)123);
@ -518,6 +558,16 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored))
CHECK_FORMAT_1("%5.7zu", "0000123", (size_t)123); CHECK_FORMAT_1("%5.7zu", "0000123", (size_t)123);
CHECK_FORMAT_1("%5.7x", "000007b", (int)123); CHECK_FORMAT_1("%5.7x", "000007b", (int)123);
CHECK_FORMAT_1("%5.7d", "-0000123", (int)-123);
CHECK_FORMAT_1("%5.7i", "-0000123", (int)-123);
CHECK_FORMAT_1("%5.7ld", "-0000123", (long)-123);
CHECK_FORMAT_1("%5.7li", "-0000123", (long)-123);
CHECK_FORMAT_1("%5.7lld", "-0000123", (long long)-123);
CHECK_FORMAT_1("%5.7lli", "-0000123", (long long)-123);
CHECK_FORMAT_1("%5.7zd", "-0000123", (Py_ssize_t)-123);
CHECK_FORMAT_1("%5.7zi", "-0000123", (Py_ssize_t)-123);
CHECK_FORMAT_1("%9.10x", "00ffffff85", (int)-123);
// Integers: precision > width > length, 0-flag // Integers: precision > width > length, 0-flag
CHECK_FORMAT_1("%05.7d", "0000123", (int)123); CHECK_FORMAT_1("%05.7d", "0000123", (int)123);
CHECK_FORMAT_1("%05.7i", "0000123", (int)123); CHECK_FORMAT_1("%05.7i", "0000123", (int)123);
@ -533,6 +583,16 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored))
CHECK_FORMAT_1("%05.7zu", "0000123", (size_t)123); CHECK_FORMAT_1("%05.7zu", "0000123", (size_t)123);
CHECK_FORMAT_1("%05.7x", "000007b", (int)123); CHECK_FORMAT_1("%05.7x", "000007b", (int)123);
CHECK_FORMAT_1("%05.7d", "-0000123", (int)-123);
CHECK_FORMAT_1("%05.7i", "-0000123", (int)-123);
CHECK_FORMAT_1("%05.7ld", "-0000123", (long)-123);
CHECK_FORMAT_1("%05.7li", "-0000123", (long)-123);
CHECK_FORMAT_1("%05.7lld", "-0000123", (long long)-123);
CHECK_FORMAT_1("%05.7lli", "-0000123", (long long)-123);
CHECK_FORMAT_1("%05.7zd", "-0000123", (Py_ssize_t)-123);
CHECK_FORMAT_1("%05.7zi", "-0000123", (Py_ssize_t)-123);
CHECK_FORMAT_1("%09.10x", "00ffffff85", (int)-123);
// Integers: precision = 0, arg = 0 (empty string in C) // Integers: precision = 0, arg = 0 (empty string in C)
CHECK_FORMAT_1("%.0d", "0", (int)0); CHECK_FORMAT_1("%.0d", "0", (int)0);
CHECK_FORMAT_1("%.0i", "0", (int)0); CHECK_FORMAT_1("%.0i", "0", (int)0);

View file

@ -2481,21 +2481,34 @@ unicode_fromformat_arg(_PyUnicodeWriter *writer,
} }
assert(len >= 0); assert(len >= 0);
if (precision < len) int negative = (buffer[0] == '-');
precision = len; len -= negative;
precision = Py_MAX(precision, len);
width = Py_MAX(width, precision + negative);
arglen = Py_MAX(precision, width); arglen = Py_MAX(precision, width);
if (_PyUnicodeWriter_Prepare(writer, arglen, 127) == -1) if (_PyUnicodeWriter_Prepare(writer, arglen, 127) == -1)
return NULL; return NULL;
if (width > precision) { if (width > precision) {
Py_UCS4 fillchar; if (negative && zeropad) {
fill = width - precision; if (_PyUnicodeWriter_WriteChar(writer, '-') == -1)
fillchar = zeropad?'0':' '; return NULL;
}
Py_UCS4 fillchar = zeropad?'0':' ';
fill = width - precision - negative;
if (PyUnicode_Fill(writer->buffer, writer->pos, fill, fillchar) == -1) if (PyUnicode_Fill(writer->buffer, writer->pos, fill, fillchar) == -1)
return NULL; return NULL;
writer->pos += fill; writer->pos += fill;
if (negative && !zeropad) {
if (_PyUnicodeWriter_WriteChar(writer, '-') == -1)
return NULL;
}
} }
if (precision > len) { if (precision > len) {
fill = precision - len; fill = precision - len;
if (PyUnicode_Fill(writer->buffer, writer->pos, fill, '0') == -1) if (PyUnicode_Fill(writer->buffer, writer->pos, fill, '0') == -1)
@ -2503,7 +2516,7 @@ unicode_fromformat_arg(_PyUnicodeWriter *writer,
writer->pos += fill; writer->pos += fill;
} }
if (_PyUnicodeWriter_WriteASCIIString(writer, buffer, len) < 0) if (_PyUnicodeWriter_WriteASCIIString(writer, &buffer[negative], len) < 0)
return NULL; return NULL;
break; break;
} }