From 022f01137f06bea7f9f34eab8b4c1acc2a03f7a0 Mon Sep 17 00:00:00 2001 From: Keith Marshall Date: Sun, 30 Oct 2016 16:35:51 +0000 Subject: [PATCH] Fix a potentially infinite printf() format conversion loop. --- mingwrt/ChangeLog | 9 ++ mingwrt/mingwex/stdio/pformat.c | 203 ++++++++++++++++++++-------------------- 2 files changed, 113 insertions(+), 99 deletions(-) diff --git a/mingwrt/ChangeLog b/mingwrt/ChangeLog index ccc3a63..90cc70a 100644 --- a/mingwrt/ChangeLog +++ b/mingwrt/ChangeLog @@ -1,3 +1,12 @@ +2016-10-30 Keith Marshall + + Fix a potentially infinite printf() format conversion loop. + + * mingwex/stdio/pformat.c (__pformat_emit_xfloat) + [value.__pformat_fpreg_mantissa == 0]: Do not attempt to normalize + it; there are no 1-bits to promote, so repeated shifting until one + appears in most significant position will never terminate. + 2016-10-17 Keith Marshall Prepare and tag mingwrt-3.22.4 patch release. diff --git a/mingwrt/mingwex/stdio/pformat.c b/mingwrt/mingwex/stdio/pformat.c index 593e712..d5c024f 100644 --- a/mingwrt/mingwex/stdio/pformat.c +++ b/mingwrt/mingwex/stdio/pformat.c @@ -1434,121 +1434,126 @@ void __pformat_emit_xfloat( __pformat_fpreg_t value, __pformat_t *stream ) * be placed before the radix point, leaving at most 15 digits * to satisfy any requested precision; thus... */ - if( (stream->precision >= 0) && (stream->precision < 15) ) + if( value.__pformat_fpreg_mantissa ) { - /* When the user specifies a precision within this range, - * we want to adjust the mantissa, to retain just the number - * of digits required, rounding up when the high bit of the - * leftmost discarded digit is set; (mask of 0x08 accounts - * for exactly one digit discarded, shifting 4 bits per - * digit, with up to 14 additional digits, to consume the - * full availability of 15 precision digits). - * - * However, before we perform the rounding operation, we - * normalise the mantissa, shifting it to the left by as many - * bit positions may be necessary, until its highest order bit - * is set, thus preserving the maximum number of bits in the - * rounded result as possible. - */ - while( value.__pformat_fpreg_mantissa < (LLONG_MAX + 1ULL) ) - value.__pformat_fpreg_mantissa <<= 1; - - /* We then shift the mantissa one bit position back to the - * right, to guard against possible overflow when the rounding - * adjustment is added. - */ - value.__pformat_fpreg_mantissa >>= 1; - - /* We now add the rounding adjustment, noting that to keep the - * 0x08 mask aligned with the shifted mantissa, we also need to - * shift it right by one bit initially, changing its starting - * value to 0x04... - */ - value.__pformat_fpreg_mantissa += 0x04LL << (4 * (14 - stream->precision)); - if( (value.__pformat_fpreg_mantissa & (LLONG_MAX + 1ULL)) == 0ULL ) - /* - * When the rounding adjustment would not have overflowed, - * then we shift back to the left again, to fill the vacated - * bit we reserved to accommodate the carry. + /* ...provided the mantissa is non-zero... + */ + if( (stream->precision >= 0) && (stream->precision < 15) ) + { + /* ...when the user specifies a precision within this range, + * we want to adjust the mantissa, to retain just the number + * of digits required, rounding up when the high bit of the + * leftmost discarded digit is set; (mask of 0x08 accounts + * for exactly one digit discarded, shifting 4 bits per + * digit, with up to 14 additional digits, to consume the + * full availability of 15 precision digits). + * + * However, before we perform the rounding operation, we + * normalise the mantissa, shifting it to the left by as many + * bit positions may be necessary, until its highest order bit + * is set, thus preserving the maximum number of bits in the + * rounded result as possible. */ - value.__pformat_fpreg_mantissa <<= 1; + while( value.__pformat_fpreg_mantissa < (LLONG_MAX + 1ULL) ) + value.__pformat_fpreg_mantissa <<= 1; - else - /* Otherwise the rounding adjustment would have overflowed, - * so the carry has already filled the vacated bit; the effect - * of this is equivalent to an increment of the exponent. + /* We then shift the mantissa one bit position back to the + * right, to guard against possible overflow when the rounding + * adjustment is added. */ - value.__pformat_fpreg_exponent++; - - /* We now complete the rounding to the required precision, by - * shifting the unwanted digits out, from the right hand end of - * the mantissa. - */ - value.__pformat_fpreg_mantissa >>= 4 * (15 - stream->precision); - } + value.__pformat_fpreg_mantissa >>= 1; - /* Encode the significant digits of the mantissa in hexadecimal - * ASCII notation, ready for transfer to the output stream... - */ - while( value.__pformat_fpreg_mantissa ) - { - /* taking the rightmost digit in each pass... - */ - int c = value.__pformat_fpreg_mantissa & 0xF; - if( c == value.__pformat_fpreg_mantissa ) - { - /* inserting the radix point, when we reach the last, - * (i.e. the most significant digit), unless we found no - * less significant digits, with no mandatory radix point - * inclusion, and no additional required precision... + /* We now add the rounding adjustment, noting that to keep the + * 0x08 mask aligned with the shifted mantissa, we also need to + * shift it right by one bit initially, changing its starting + * value to 0x04... */ - if( (p > buf) - || (stream->flags & PFORMAT_HASHED) || (stream->precision > 0) ) + value.__pformat_fpreg_mantissa += 0x04LL << (4 * (14 - stream->precision)); + if( (value.__pformat_fpreg_mantissa & (LLONG_MAX + 1ULL)) == 0ULL ) /* - * Internally, we represent the radix point as an ASCII '.'; - * we will replace it with any locale specific alternative, - * at the time of transfer to the ultimate destination. + * When the rounding adjustment would not have overflowed, + * then we shift back to the left again, to fill the vacated + * bit we reserved to accommodate the carry. */ - *p++ = '.'; + value.__pformat_fpreg_mantissa <<= 1; - /* If the most significant hexadecimal digit of the encoded - * output value is greater than one, then the indicated value - * will appear too large, by an additional binary exponent - * corresponding to the number of higher order bit positions - * which it occupies... + else + /* Otherwise the rounding adjustment would have overflowed, + * so the carry has already filled the vacated bit; the effect + * of this is equivalent to an increment of the exponent. + */ + value.__pformat_fpreg_exponent++; + + /* We now complete the rounding to the required precision, by + * shifting the unwanted digits out, from the right hand end of + * the mantissa. + */ + value.__pformat_fpreg_mantissa >>= 4 * (15 - stream->precision); + } + + /* Encode the significant digits of the mantissa in hexadecimal + * ASCII notation, ready for transfer to the output stream... + */ + while( value.__pformat_fpreg_mantissa ) + { + /* taking the rightmost digit in each pass... */ - while( value.__pformat_fpreg_mantissa > 1 ) + int c = value.__pformat_fpreg_mantissa & 0xF; + if( c == value.__pformat_fpreg_mantissa ) { - /* so reduce the exponent value to compensate... + /* inserting the radix point, when we reach the last, + * (i.e. the most significant digit), unless we found no + * less significant digits, with no mandatory radix point + * inclusion, and no additional required precision... */ - value.__pformat_fpreg_exponent--; - value.__pformat_fpreg_mantissa >>= 1; + if( (p > buf) + || (stream->flags & PFORMAT_HASHED) || (stream->precision > 0) ) + /* + * Internally, we represent the radix point as an ASCII '.'; + * we will replace it with any locale specific alternative, + * at the time of transfer to the ultimate destination. + */ + *p++ = '.'; + + /* If the most significant hexadecimal digit of the encoded + * output value is greater than one, then the indicated value + * will appear too large, by an additional binary exponent + * corresponding to the number of higher order bit positions + * which it occupies... + */ + while( value.__pformat_fpreg_mantissa > 1 ) + { + /* so reduce the exponent value to compensate... + */ + value.__pformat_fpreg_exponent--; + value.__pformat_fpreg_mantissa >>= 1; + } } - } - else if( stream->precision > 0 ) - /* - * we have not yet fulfilled the desired precision, - * and we have not yet found the most significant digit, - * so account for the current digit, within the field - * width required to meet the specified precision. - */ - stream->precision--; + else if( stream->precision > 0 ) + /* + * we have not yet fulfilled the desired precision, + * and we have not yet found the most significant digit, + * so account for the current digit, within the field + * width required to meet the specified precision. + */ + stream->precision--; - if( (c > 0) || (p > buf) || (stream->precision >= 0) ) - /* - * Ignoring insignificant trailing zeros, (unless required to - * satisfy specified precision), store the current encoded digit - * into the pending output buffer, in LIFO order, and using the - * appropriate case for digits in the `A'..`F' range. - */ - *p++ = c > 9 ? (c - 10 + 'A') | (stream->flags & PFORMAT_XCASE) : c + '0'; + if( (c > 0) || (p > buf) || (stream->precision >= 0) ) + /* + * Ignoring insignificant trailing zeros, (unless required to + * satisfy specified precision), store the current encoded digit + * into the pending output buffer, in LIFO order, and using the + * appropriate case for digits in the `A'..`F' range. + */ + *p++ = c > 9 ? (c - 10 + 'A') | (stream->flags & PFORMAT_XCASE) : c + '0'; - /* Shift out the current digit, (4-bit logical shift right), - * to align the next more significant digit to be extracted, - * and encoded in the next pass. - */ - value.__pformat_fpreg_mantissa >>= 4; + /* Shift out the current digit, (4-bit logical shift right), + * to align the next more significant digit to be extracted, + * and encoded in the next pass. + */ + value.__pformat_fpreg_mantissa >>= 4; + } } if( p == buf ) -- 2.11.0