Endless loop in CFGAS_FormatString::FormatStrNum().
Comparison didn't take sign into account, nor the possibility
of CFGAS_Decimal overflowing to 0 (fixing that should be a
separate issue).
Fix another obvious overflow while computing threshold.
Bug: pdfium:1244
Change-Id: Idbbfd311a60b57f83b18ee2fa8af45eeafa877f8
Reviewed-on: https://pdfium-review.googlesource.com/c/50894
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/xfa/fgas/crt/cfgas_decimal.h b/xfa/fgas/crt/cfgas_decimal.h
index ddfd8e8..4751c5b 100644
--- a/xfa/fgas/crt/cfgas_decimal.h
+++ b/xfa/fgas/crt/cfgas_decimal.h
@@ -25,6 +25,7 @@
CFGAS_Decimal operator*(const CFGAS_Decimal& val) const;
CFGAS_Decimal operator/(const CFGAS_Decimal& val) const;
+ bool IsNotZero() const { return m_uHi || m_uMid || m_uLo; }
uint8_t GetScale() const { return m_uScale; }
void SetScale(uint8_t newScale);
void SetNegate();
@@ -35,7 +36,6 @@
uint32_t lo,
bool neg,
uint8_t scale);
- bool IsNotZero() const { return m_uHi || m_uMid || m_uLo; }
uint32_t m_uHi = 0;
uint32_t m_uMid = 0;
diff --git a/xfa/fgas/crt/cfgas_formatstring.cpp b/xfa/fgas/crt/cfgas_formatstring.cpp
index 7cc6d93..45e0445 100644
--- a/xfa/fgas/crt/cfgas_formatstring.cpp
+++ b/xfa/fgas/crt/cfgas_formatstring.cpp
@@ -11,6 +11,7 @@
#include <vector>
#include "core/fxcrt/fx_extension.h"
+#include "core/fxcrt/fx_safe_types.h"
#include "xfa/fgas/crt/cfgas_decimal.h"
#define FX_LOCALECATEGORY_DateHash 0xbde9abde
@@ -1896,25 +1897,30 @@
}
}
- int threshold = 1;
+ FX_SAFE_UINT32 threshold = 1;
while (fixed_count > 1) {
threshold *= 10;
fixed_count--;
}
- if (decimal.ToDouble() != 0.0) {
- if (decimal.ToDouble() < threshold) {
- decimal = decimal * CFGAS_Decimal(10);
- exponent = -1;
- while (decimal.ToDouble() < threshold) {
- decimal = decimal * CFGAS_Decimal(10);
- exponent -= 1;
- }
- } else if (decimal.ToDouble() > threshold) {
- threshold *= 10;
- while (decimal.ToDouble() > threshold) {
- decimal = decimal / CFGAS_Decimal(10);
- exponent += 1;
- }
+ if (!threshold.IsValid())
+ return false;
+
+ bool bAdjusted = false;
+ while (decimal.IsNotZero() &&
+ fabs(decimal.ToDouble()) < threshold.ValueOrDie()) {
+ decimal = decimal * CFGAS_Decimal(10);
+ --exponent;
+ bAdjusted = true;
+ }
+ if (!bAdjusted) {
+ threshold *= 10;
+ if (!threshold.IsValid())
+ return false;
+
+ while (decimal.IsNotZero() &&
+ fabs(decimal.ToDouble()) > threshold.ValueOrDie()) {
+ decimal = decimal / CFGAS_Decimal(10);
+ ++exponent;
}
}
}
@@ -2077,14 +2083,12 @@
}
if (bNeg)
*wsOutput = pLocale->GetMinusSymbol() + *wsOutput;
-
- return false;
+ return true;
}
if (dot_index_f ==
pdfium::base::checked_cast<int32_t>(wsNumFormat.GetLength())) {
if (!bAddNeg && bNeg)
*wsOutput = pLocale->GetMinusSymbol() + *wsOutput;
-
return true;
}
diff --git a/xfa/fgas/crt/cfgas_formatstring_unittest.cpp b/xfa/fgas/crt/cfgas_formatstring_unittest.cpp
index 8bc77a5..a3b7bd4 100644
--- a/xfa/fgas/crt/cfgas_formatstring_unittest.cpp
+++ b/xfa/fgas/crt/cfgas_formatstring_unittest.cpp
@@ -303,12 +303,14 @@
}
TEST_F(CFGAS_FormatStringTest, NumParse) {
- struct {
+ struct TestCase {
const wchar_t* locale;
const wchar_t* input;
const wchar_t* pattern;
const wchar_t* output;
- } tests[] = {
+ };
+
+ static const TestCase tests[] = {
// {L"en", L"€100.00", L"num(en_GB){$z,zz9.99}", L"100"},
// {L"en", L"1050", L"99V99", L"10.50"},
// {L"en", L"3125", L"99V99", L"31.25"},
@@ -415,22 +417,24 @@
{L"en", L"123.545,4", L"zzz.zzz,z", L"123.5454"},
};
- for (size_t i = 0; i < FX_ArraySize(tests); ++i) {
+ for (const auto& test : tests) {
WideString result;
- EXPECT_TRUE(fmt(tests[i].locale)
- ->ParseNum(tests[i].input, tests[i].pattern, &result))
- << " TEST: " << i;
- EXPECT_STREQ(tests[i].output, result.c_str()) << " TEST: " << i;
+ EXPECT_TRUE(fmt(test.locale)->ParseNum(test.input, test.pattern, &result))
+ << " TEST: " << test.input << ", " << test.pattern;
+ EXPECT_STREQ(test.output, result.c_str())
+ << " TEST: " << test.input << ", " << test.pattern;
}
}
TEST_F(CFGAS_FormatStringTest, NumFormat) {
- struct {
+ struct TestCase {
const wchar_t* locale;
const wchar_t* input;
const wchar_t* pattern;
const wchar_t* output;
- } tests[] = {
+ };
+
+ static const TestCase tests[] = {
{L"en", L"1.234", L"zz9.zzz", L"1.234"},
{L"en", L"1", L"num{z 'text'}", L"1 text"},
{L"en", L"1", L"num{'text' z}", L"text 1"},
@@ -518,14 +522,21 @@
{L"en", L"1", L"9.C", L"1"},
{L"en", L"1", L"9.d", L"1"},
{L"en", L"1", L"9.D", L"1"},
+ // https://crbug.com/pdfium/1244
+ {L"en", L"1", L"E", L"1"},
+ {L"en", L"0", L"E", L"0"},
+ {L"en", L"-1", L"E", L"-1"},
+ {L"en", L"900000000000000000000", L"E", L"900,000,000,000,000,000,000"},
+ // TODO(tsepez): next one seems wrong
+ // {L"en", L".000000000000000000009", L"E", L"9"},
};
- for (size_t i = 0; i < FX_ArraySize(tests); ++i) {
+ for (const auto& test : tests) {
WideString result;
- EXPECT_TRUE(fmt(tests[i].locale)
- ->FormatNum(tests[i].input, tests[i].pattern, &result))
- << " TEST: " << i;
- EXPECT_STREQ(tests[i].output, result.c_str()) << " TEST: " << i;
+ EXPECT_TRUE(fmt(test.locale)->FormatNum(test.input, test.pattern, &result))
+ << " TEST: " << test.input << ", " << test.pattern;
+ EXPECT_STREQ(test.output, result.c_str())
+ << " TEST: " << test.input << ", " << test.pattern;
}
}