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.
This commit is contained in:
Tim Peters 2001-04-12 00:35:51 +00:00
parent 4642cb9ac9
commit 711088d9b8
3 changed files with 53 additions and 25 deletions

View file

@ -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

View file

@ -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++;
}

View file

@ -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++;
}