Skip to content

Commit 910bb20

Browse files
FrankYFTangmihnita
authored andcommitted
ICU-23256 Fix floating exception while divided by 0
See #3769
1 parent a08339b commit 910bb20

5 files changed

Lines changed: 34 additions & 6 deletions

File tree

icu4c/source/i18n/nfrule.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,12 +158,17 @@ NFRule::makeRules(UnicodeString& description,
158158
UnicodeString sbuf;
159159
int32_t orElseOp = description.indexOf(gVerticalLine);
160160

161+
uint64_t mod = util64_pow(rule1->radix, rule1->exponent);
161162
// we'll actually only split the rule into two rules if its
162163
// base value is an even multiple of its divisor (or it's one
163164
// of the special rules)
165+
if (rule1->baseValue > 0 && rule1->radix != 0 && mod == 0) {
166+
status = U_NUMBER_ARG_OUTOFBOUNDS_ERROR;
167+
return;
168+
}
164169
if ((rule1->baseValue > 0
165170
&& (rule1->radix != 0) // ICU-23109 Ensure next line won't "% 0"
166-
&& (rule1->baseValue % util64_pow(rule1->radix, rule1->exponent)) == 0)
171+
&& (rule1->baseValue % mod == 0))
167172
|| rule1->getType() == kImproperFractionRule
168173
|| rule1->getType() == kDefaultRule) {
169174

icu4c/source/test/intltest/itrbnf.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ void IntlTestRBNF::runIndexedTest(int32_t index, UBool exec, const char* &name,
8686
TESTCASE(34, testOmissionReplacementWithPluralRules);
8787
TESTCASE(35, TestNullDereferenceWRITE23149);
8888
TESTCASE(36, TestNullDereferenceREAD23184);
89+
TESTCASE(39, TestDividedByZero);
8990
#else
9091
TESTCASE(0, TestRBNFDisabled);
9192
#endif
@@ -2781,6 +2782,14 @@ IntlTestRBNF::TestNullDereferenceREAD23184() {
27812782
}
27822783
}
27832784

2785+
void
2786+
IntlTestRBNF::TestDividedByZero() {
2787+
UParseError perror;
2788+
UErrorCode status = U_ZERO_ERROR;
2789+
RuleBasedNumberFormat rbnf(u"7060920374060940374/4:[]", Locale::getUS(), perror, status);
2790+
assertEquals("base is too large", U_NUMBER_ARG_OUTOFBOUNDS_ERROR, status);
2791+
}
2792+
27842793
/* U_HAVE_RBNF */
27852794
#else
27862795

icu4c/source/test/intltest/itrbnf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ class IntlTestRBNF : public IntlTest {
167167
void testOmissionReplacementWithPluralRules();
168168
void TestNullDereferenceWRITE23149();
169169
void TestNullDereferenceREAD23184();
170+
void TestDividedByZero();
170171

171172
protected:
172173
virtual void doTest(RuleBasedNumberFormat* formatter, const char* const testData[][2], UBool testParsing);

icu4j/main/core/src/main/java/com/ibm/icu/text/NFRule.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -164,14 +164,16 @@ public static void makeRules(String description,
164164
StringBuilder sbuf = new StringBuilder();
165165
int orElseOp = description.indexOf('|');
166166

167+
long mod = power(rule1.radix, rule1.exponent);
168+
if (rule1.baseValue > 0 && mod == 0) {
169+
throw new IllegalArgumentException("value out of range");
170+
}
167171
// we'll actually only split the rule into two rules if its
168172
// base value is an even multiple of its divisor (or it's one
169173
// of the special rules)
170-
if ((rule1.baseValue > 0
171-
&& rule1.baseValue % (power(rule1.radix, rule1.exponent)) == 0)
172-
|| rule1.baseValue == IMPROPER_FRACTION_RULE
173-
|| rule1.baseValue == DEFAULT_RULE)
174-
{
174+
if ((rule1.baseValue > 0 && rule1.baseValue % mod == 0)
175+
|| rule1.baseValue == IMPROPER_FRACTION_RULE
176+
|| rule1.baseValue == DEFAULT_RULE) {
175177

176178
// if it passes that test, new up the second rule. If the
177179
// rule set both rules will belong to is a fraction rule

icu4j/main/core/src/test/java/com/ibm/icu/dev/test/format/RBNFParseTest.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,17 @@ public void Test23184EmptyRuleSet() {
213213
public void TestNullRuleSet() {
214214
try {
215215
RuleBasedNumberFormat rbnf = new RuleBasedNumberFormat("x00:a>>>b>#>", Locale.US);
216+
errln("Failed: should throw IllegalArgumentException");
217+
} catch (IllegalArgumentException e) {
218+
// success!
219+
}
220+
}
221+
222+
@Test
223+
public void TestDividedByZero() {
224+
try {
225+
RuleBasedNumberFormat rbnf = new RuleBasedNumberFormat("7060920374060940374/4:[]");
226+
errln("Failed: should throw IllegalArgumentException");
216227
} catch (IllegalArgumentException e) {
217228
// success!
218229
}

0 commit comments

Comments
 (0)