Skip to content

Commit 6ccd8ad

Browse files
committed
ICU-23256 Fix floating exception while divided by 0
See #3769
1 parent 026458b commit 6ccd8ad

File tree

5 files changed

+32
-2
lines changed

5 files changed

+32
-2
lines changed

icu4c/source/i18n/nfrule.cpp

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

154+
uint64_t mod = util64_pow(rule1->radix, rule1->exponent);
154155
// we'll actually only split the rule into two rules if its
155156
// base value is an even multiple of its divisor (or it's one
156157
// of the special rules)
158+
if (rule1->baseValue > 0 && rule1->radix != 0 && mod == 0) {
159+
status = U_NUMBER_ARG_OUTOFBOUNDS_ERROR;
160+
return;
161+
}
157162
if ((rule1->baseValue > 0
158163
&& (rule1->radix != 0) // ICU-23109 Ensure next line won't "% 0"
159-
&& (rule1->baseValue % util64_pow(rule1->radix, rule1->exponent)) == 0)
164+
&& (rule1->baseValue % mod == 0))
160165
|| rule1->getType() == kImproperFractionRule
161166
|| rule1->getType() == kDefaultRule) {
162167

icu4c/source/test/intltest/itrbnf.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ void IntlTestRBNF::runIndexedTest(int32_t index, UBool exec, const char* &name,
8888
TESTCASE(36, TestNullDereferenceREAD23184);
8989
TESTCASE(37, TestUnparseableConflictingSubstitutions);
9090
TESTCASE(38, TestAmbiguousDelimiter);
91+
TESTCASE(39, TestDividedByZero);
9192
#else
9293
TESTCASE(0, TestRBNFDisabled);
9394
#endif
@@ -2818,6 +2819,14 @@ IntlTestRBNF::TestAmbiguousDelimiter() {
28182819
}
28192820
}
28202821

2822+
void
2823+
IntlTestRBNF::TestDividedByZero() {
2824+
UParseError perror;
2825+
UErrorCode status = U_ZERO_ERROR;
2826+
RuleBasedNumberFormat rbnf(u"7060920374060940374/4:[]", Locale::getUS(), perror, status);
2827+
assertEquals("base is too large", U_NUMBER_ARG_OUTOFBOUNDS_ERROR, status);
2828+
}
2829+
28212830
/* U_HAVE_RBNF */
28222831
#else
28232832

icu4c/source/test/intltest/itrbnf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ class IntlTestRBNF : public IntlTest {
169169
void TestNullDereferenceREAD23184();
170170
void TestUnparseableConflictingSubstitutions();
171171
void TestAmbiguousDelimiter();
172+
void TestDividedByZero();
172173

173174
protected:
174175
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: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,10 +131,14 @@ public static void makeRules(
131131
StringBuilder sbuf = new StringBuilder();
132132
int orElseOp = description.indexOf('|');
133133

134+
long mod = power(rule1.radix, rule1.exponent);
135+
if (rule1.baseValue > 0 && mod == 0) {
136+
throw new IllegalArgumentException("value out of range");
137+
}
134138
// we'll actually only split the rule into two rules if its
135139
// base value is an even multiple of its divisor (or it's one
136140
// of the special rules)
137-
if ((rule1.baseValue > 0 && rule1.baseValue % (power(rule1.radix, rule1.exponent)) == 0)
141+
if ((rule1.baseValue > 0 && rule1.baseValue % mod == 0)
138142
|| rule1.baseValue == IMPROPER_FRACTION_RULE
139143
|| rule1.baseValue == DEFAULT_RULE) {
140144

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
@@ -212,6 +212,17 @@ public void Test23184EmptyRuleSet() {
212212
public void TestNullRuleSet() {
213213
try {
214214
RuleBasedNumberFormat rbnf = new RuleBasedNumberFormat("x00:a>>>b>#>", Locale.US);
215+
errln("Failed: should throw IllegalArgumentException");
216+
} catch (IllegalArgumentException e) {
217+
// success!
218+
}
219+
}
220+
221+
@Test
222+
public void TestDividedByZero() {
223+
try {
224+
RuleBasedNumberFormat rbnf = new RuleBasedNumberFormat("7060920374060940374/4:[]");
225+
errln("Failed: should throw IllegalArgumentException");
215226
} catch (IllegalArgumentException e) {
216227
// success!
217228
}

0 commit comments

Comments
 (0)