diff options
author | claireho <chinglanho@gmail.com> | 2011-08-23 16:51:57 -0700 |
---|---|---|
committer | claireho <chinglanho@gmail.com> | 2011-08-23 17:03:04 -0700 |
commit | 3ef011cb2ded20c46f764e284c6a10f49a9923f8 (patch) | |
tree | e5aa31fd3e208dc1c501225ac7981c5190e1eed3 | |
parent | c53bf83a40a6888f5b246a73f13f6c919de1f5f9 (diff) | |
download | icu4c-3ef011cb2ded20c46f764e284c6a10f49a9923f8.tar.gz |
Fix the crash in ICU called by DecimalFormat.parse().
Bug:5203447
Fixed a pointer reference that is out of scope.
For details, see ICU bug http://bugs.icu-project.org/trac/ticket/8199.
Changes passed the relevant libcore and harmony tests wo new failures.
Change-Id: Id05313654de6113df39a58bf52f7bb600eac7861
-rw-r--r-- | i18n/digitlst.cpp | 42 |
1 files changed, 25 insertions, 17 deletions
diff --git a/i18n/digitlst.cpp b/i18n/digitlst.cpp index 56c7144d..783faae0 100644 --- a/i18n/digitlst.cpp +++ b/i18n/digitlst.cpp @@ -493,13 +493,17 @@ int32_t DigitList::getLong() /*const*/ return result; } - /** - * convert this number to an int64_t. Round if there is a fractional part. + * convert this number to an int64_t. Truncate if there is a fractional part. * Return zero if the number cannot be represented. */ int64_t DigitList::getInt64() /*const*/ { - // Round if non-integer. (Truncate or round?) + // BEGIN android-change + // Apply the changes for ICU ticket#8199 to avoid the crash in DigitList::getInt64(). + // The fixes are in ICU4.8. + // See http://bugs.icu-project.org/trac/ticket/8199 for details. + + // Truncate if non-integer. // Return 0 if out of range. // Range of in64_t is -9223372036854775808 to 9223372036854775807 (19 digits) // @@ -507,23 +511,27 @@ int64_t DigitList::getInt64() /*const*/ { // Overflow, absolute value too big. return 0; } - decNumber *workingNum = fDecNumber; - if (fDecNumber->exponent != 0) { - // Force to an integer, with zero exponent, rounding if necessary. - DigitList copy(*this); - DigitList zero; - uprv_decNumberQuantize(copy.fDecNumber, copy.fDecNumber, zero.fDecNumber, &fContext); - workingNum = copy.fDecNumber; - } + // The number of integer digits may differ from the number of digits stored + // in the decimal number. + // for 12.345 numIntDigits = 2, number->digits = 5 + // for 12E4 numIntDigits = 6, number->digits = 2 + // The conversion ignores the fraction digits in the first case, + // and fakes up extra zero digits in the second. + // TODO: It would be faster to store a table of powers of ten to multiply by + // instead of looping over zero digits, multiplying each time. + int32_t numIntDigits = fDecNumber->digits + fDecNumber->exponent; uint64_t value = 0; - int32_t numDigits = workingNum->digits; - for (int i = numDigits-1; i>=0 ; --i) { - int v = workingNum->lsu[i]; + for (int32_t i = 0; i < numIntDigits; i++) { + // Loop is iterating over digits starting with the most significant. + // Numbers are stored with the least significant digit at index zero. + int32_t digitIndex = fDecNumber->digits - i - 1; + int32_t v = (digitIndex >= 0) ? fDecNumber->lsu[digitIndex] : 0; value = value * (uint64_t)10 + (uint64_t)v; } - if (decNumberIsNegative(workingNum)) { + + if (decNumberIsNegative(fDecNumber)) { value = ~value; value += 1; } @@ -532,17 +540,17 @@ int64_t DigitList::getInt64() /*const*/ { // Check overflow. It's convenient that the MSD is 9 only on overflow, the amount of // overflow can't wrap too far. The test will also fail -0, but // that does no harm; the right answer is 0. - if (numDigits == 19) { + if (numIntDigits == 19) { if (( decNumberIsNegative(fDecNumber) && svalue>0) || (!decNumberIsNegative(fDecNumber) && svalue<0)) { svalue = 0; } } + // END android-change return svalue; } - /** * Return a string form of this number. * Format is as defined by the decNumber library, for interchange of |