aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorclaireho <chinglanho@gmail.com>2011-08-23 16:51:57 -0700
committerclaireho <chinglanho@gmail.com>2011-08-23 17:03:04 -0700
commit3ef011cb2ded20c46f764e284c6a10f49a9923f8 (patch)
treee5aa31fd3e208dc1c501225ac7981c5190e1eed3
parentc53bf83a40a6888f5b246a73f13f6c919de1f5f9 (diff)
downloadicu4c-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.cpp42
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