From 711088d9b8c6898aad571fb251cb40a8b7d42f64 Mon Sep 17 00:00:00 2001 From: Tim Peters Date: Thu, 12 Apr 2001 00:35:51 +0000 Subject: [PATCH] Fix for SF bug #415514: "%#x" % 0 caused assertion failure/abort. http://sourceforge.net/tracker/index.php?func=detail&aid=415514&group_id=5470&atid=105470 For short ints, Python defers to the platform C library to figure out what %#x should do. The code asserted that the platform C returned a string beginning with "0x". However, that's not true when-- and only when --the *value* being formatted is 0. Changed the code to live with C's inconsistency here. In the meantime, the problem does not arise if you format a long 0 (0L) instead. However, that's because the code *we* wrote to do %#x conversions on longs produces a leading "0x" regardless of value. That's probably wrong too: we should drop leading "0x", for consistency with C, when (& only when) formatting 0L. So I changed the long formatting code to do that too. --- Lib/test/test_format.py | 16 ++++++++++++++++ Objects/stringobject.c | 39 +++++++++++++++++++++++++-------------- Objects/unicodeobject.c | 23 ++++++++++++----------- 3 files changed, 53 insertions(+), 25 deletions(-) diff --git a/Lib/test/test_format.py b/Lib/test/test_format.py index 6a6060384b9..ce5d5f2c807 100644 --- a/Lib/test/test_format.py +++ b/Lib/test/test_format.py @@ -164,6 +164,22 @@ def testboth(formatstr, *args): testboth("%d", -42, "-42") testboth("%d", 42L, "42") testboth("%d", -42L, "-42") +testboth("%#x", 1, "0x1") +testboth("%#x", 1L, "0x1") +testboth("%#X", 1, "0X1") +testboth("%#X", 1L, "0X1") +testboth("%#o", 1, "01") +testboth("%#o", 1L, "01") +testboth("%#o", 0, "0") +testboth("%#o", 0L, "0") +testboth("%o", 0, "0") +testboth("%o", 0L, "0") +testboth("%d", 0, "0") +testboth("%d", 0L, "0") +testboth("%#x", 0, "0") +testboth("%#x", 0L, "0") +testboth("%#X", 0, "0") +testboth("%#X", 0L, "0") testboth("%x", 0x42, "42") # testboth("%x", -0x42, "ffffffbe") # Alas, that's specific to 32-bit machines diff --git a/Objects/stringobject.c b/Objects/stringobject.c index 740cbe294e4..8e1153693d0 100644 --- a/Objects/stringobject.c +++ b/Objects/stringobject.c @@ -2575,8 +2575,16 @@ _PyString_FormatLong(PyObject *val, int flags, int prec, int type, numdigits = len - numnondigits; assert(numdigits > 0); - /* Get rid of base marker unless F_ALT */ - if ((flags & F_ALT) == 0) { + /* Get rid of base marker unless F_ALT. Even if F_ALT, leading 0x + * must be stripped if the *value* is 0. + */ + if ((flags & F_ALT) == 0 || + ((flags & F_ALT) && + (type == 'x' || type == 'X') && + numdigits == 1 && + !sign && + buf[2] == '0' + )) { /* Need to skip 0x, 0X or 0. */ int skipped = 0; switch (type) { @@ -3015,17 +3023,21 @@ PyString_Format(PyObject *format, PyObject *args) width--; } if ((flags & F_ALT) && (c == 'x' || c == 'X')) { + /* There's a base marker ("0x" or "0X") if and + * only if the value is non-zero. + */ assert(pbuf[0] == '0'); - assert(pbuf[1] == c); - if (fill != ' ') { - *res++ = *pbuf++; - *res++ = *pbuf++; + if (pbuf[1] == c) { + if (fill != ' ') { + *res++ = *pbuf++; + *res++ = *pbuf++; + } + rescnt -= 2; + width -= 2; + if (width < 0) + width = 0; + len -= 2; } - rescnt -= 2; - width -= 2; - if (width < 0) - width = 0; - len -= 2; } if (width > len && !(flags & F_LJUST)) { do { @@ -3037,9 +3049,8 @@ PyString_Format(PyObject *format, PyObject *args) if (sign) *res++ = sign; if ((flags & F_ALT) && - (c == 'x' || c == 'X')) { - assert(pbuf[0] == '0'); - assert(pbuf[1] == c); + (c == 'x' || c == 'X') && + pbuf[1] == c) { *res++ = *pbuf++; *res++ = *pbuf++; } diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index c237789a79e..aecc2618d15 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -5081,16 +5081,17 @@ PyObject *PyUnicode_Format(PyObject *format, } if ((flags & F_ALT) && (c == 'x' || c == 'X')) { assert(pbuf[0] == '0'); - assert(pbuf[1] == c); - if (fill != ' ') { - *res++ = *pbuf++; - *res++ = *pbuf++; + if (pbuf[1] == c) { + if (fill != ' ') { + *res++ = *pbuf++; + *res++ = *pbuf++; + } + rescnt -= 2; + width -= 2; + if (width < 0) + width = 0; + len -= 2; } - rescnt -= 2; - width -= 2; - if (width < 0) - width = 0; - len -= 2; } if (width > len && !(flags & F_LJUST)) { do { @@ -5101,9 +5102,9 @@ PyObject *PyUnicode_Format(PyObject *format, if (fill == ' ') { if (sign) *res++ = sign; - if ((flags & F_ALT) && (c == 'x' || c == 'X')) { + if ((flags & F_ALT) && (c == 'x' || c == 'X') && + pbuf[1] == c) { assert(pbuf[0] == '0'); - assert(pbuf[1] == c); *res++ = *pbuf++; *res++ = *pbuf++; }