Skip to content

Commit fcf9cb4

Browse files
committed
ICU-23407 Fix null pointer dereference in NumeratorSubstitution::doParse
See unicode-org#4059
1 parent 5e1ded9 commit fcf9cb4

5 files changed

Lines changed: 33 additions & 3 deletions

File tree

icu4c/source/i18n/nfsubs.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1305,7 +1305,7 @@ NumeratorSubstitution::doParse(const UnicodeString& text,
13051305
int32_t zeroCount = 0;
13061306
UnicodeString workText(text);
13071307

1308-
if (withZeros) {
1308+
if (withZeros && getRuleSet() != nullptr) {
13091309
ParsePosition workPos(1);
13101310
Formattable temp;
13111311

icu4c/source/test/intltest/itrbnfp.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ void IntlTestRBNFParse::runIndexedTest(int32_t index, UBool exec, const char* &n
3939
#if U_HAVE_RBNF
4040
TESTCASE(0, TestParse);
4141
TESTCASE(1, TestNullRuleSet);
42+
TESTCASE(2, Test23407NullDereferenceREAD);
4243
#else
4344
TESTCASE(0, TestRBNFParseDisabled);
4445
#endif
@@ -154,6 +155,22 @@ IntlTestRBNFParse::TestNullRuleSet() {
154155
}
155156
}
156157

158+
void
159+
IntlTestRBNFParse::Test23407NullDereferenceREAD() {
160+
// This is "garbage" from a fuzzer run. We test that the code does not crash.
161+
// Parse failure is expected.
162+
logln("Test23407NullDereferenceREAD");
163+
icu::UnicodeString fuzzstr(u"x0x:>%䀾>Ā;%䀾:>;>;;<0<<>");
164+
165+
UErrorCode status = U_ZERO_ERROR;
166+
UParseError perror;
167+
icu::RuleBasedNumberFormat rbfmt(fuzzstr, Locale::getUS(), perror, status);
168+
icu::Formattable result;
169+
if (U_SUCCESS(status)) {
170+
rbfmt.parse(fuzzstr, result, status);
171+
}
172+
}
173+
157174
void
158175
IntlTestRBNFParse::testfmt(RuleBasedNumberFormat* formatter, double val, UErrorCode& status) {
159176
UnicodeString us;

icu4c/source/test/intltest/itrbnfp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class IntlTestRBNFParse : public IntlTest {
3030
*/
3131
virtual void TestParse();
3232
virtual void TestNullRuleSet();
33+
virtual void Test23407NullDereferenceREAD();
3334

3435
void testfmt(RuleBasedNumberFormat* formatter, double val, UErrorCode& status);
3536
void testfmt(RuleBasedNumberFormat* formatter, int val, UErrorCode& status);

icu4j/main/common_tests/src/test/java/com/ibm/icu/dev/test/format/RbnfTest.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2346,4 +2346,16 @@ public void TestTurkishSpellout() {
23462346

23472347
doParsingTest(formatter, lpTestData, true);
23482348
}
2349+
2350+
@Test
2351+
public void Test23407NullDereferenceREAD() {
2352+
// This is "garbage" from a fuzzer run. We test that the code does not crash.
2353+
String fuzzstr = "x0x:>%䀾>Ā;%䀾:>;>;;<0<<>";
2354+
try {
2355+
RuleBasedNumberFormat rbfmt = new RuleBasedNumberFormat(fuzzstr, Locale.US);
2356+
rbfmt.parse(fuzzstr);
2357+
} catch (IllegalArgumentException | ParseException e) {
2358+
// Expected exception or parse failure is fine, but not others like NPE.
2359+
}
2360+
}
23492361
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1669,7 +1669,7 @@ public Number doParse(
16691669
// if withZeros is true, we need to count the zeros
16701670
// and use that to adjust the parse result
16711671
int zeroCount = 0;
1672-
if (withZeros) {
1672+
if (withZeros && ruleSet != null) {
16731673
String workText = text;
16741674
ParsePosition workPos = new ParsePosition(1);
16751675

@@ -1714,7 +1714,7 @@ public Number doParse(
17141714
nonNumericalExecutedRuleMask,
17151715
recursionCount);
17161716

1717-
if (withZeros) {
1717+
if (withZeros && result != null) {
17181718
// any base value will do in this case. is there a way to
17191719
// force this to not bother trying all the base values?
17201720

0 commit comments

Comments
 (0)