From 81ad37be057e66be8678e2a102cf872c26001d26 Mon Sep 17 00:00:00 2001 From: Rich Gillam <62772518+richgillam@users.noreply.github.com> Date: Thu, 24 Feb 2022 18:53:02 -0800 Subject: [PATCH] ICU-21802 Fix error where strict date parsing could succeed on certain malformed input strings. --- icu4c/source/i18n/smpdtfmt.cpp | 3 +++ icu4c/source/test/cintltst/cdattst.c | 22 +++++++++++++++++++ .../com/ibm/icu/text/SimpleDateFormat.java | 3 +++ .../icu/dev/test/format/DateFormatTest.java | 16 ++++++++++++++ 4 files changed, 44 insertions(+) diff --git a/icu4c/source/i18n/smpdtfmt.cpp b/icu4c/source/i18n/smpdtfmt.cpp index 91748d82f9f..c1e943a0949 100644 --- a/icu4c/source/i18n/smpdtfmt.cpp +++ b/icu4c/source/i18n/smpdtfmt.cpp @@ -3792,6 +3792,9 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC src = &text; } parseInt(*src, number, pos, allowNegative,currentNumberFormat); + if (!isLenient() && pos.getIndex() < start + count) { + return -start; + } if (pos.getIndex() != parseStart) { int32_t val = number.getLong(); diff --git a/icu4c/source/test/cintltst/cdattst.c b/icu4c/source/test/cintltst/cdattst.c index 00b2d6a01a1..2c5d51c64b2 100644 --- a/icu4c/source/test/cintltst/cdattst.c +++ b/icu4c/source/test/cintltst/cdattst.c @@ -45,6 +45,7 @@ static void TestFormatForFields(void); static void TestForceGannenNumbering(void); static void TestMapDateToCalFields(void); static void TestNarrowQuarters(void); +static void TestExtraneousCharacters(void); void addDateForTest(TestNode** root); @@ -67,6 +68,7 @@ void addDateForTest(TestNode** root) TESTCASE(TestForceGannenNumbering); TESTCASE(TestMapDateToCalFields); TESTCASE(TestNarrowQuarters); + TESTCASE(TestExtraneousCharacters); } /* Testing the DateFormat API */ static void TestDateFormat() @@ -2017,4 +2019,24 @@ static void TestNarrowQuarters(void) { } } +static void TestExtraneousCharacters(void) { + // regression test for ICU-21802 + UErrorCode err = U_ZERO_ERROR; + UCalendar* cal = ucal_open(u"UTC", -1, "en_US", UCAL_GREGORIAN, &err); + UDateFormat* df = udat_open(UDAT_PATTERN, UDAT_PATTERN, "en_US", u"UTC", -1, u"yyyyMMdd", -1, &err); + + if (assertSuccess("Failed to create date formatter and calendar", &err)) { + udat_setLenient(df, false); + + udat_parseCalendar(df, cal, u"2021", -1, NULL, &err); + assertTrue("Success parsing '2021'", err == U_PARSE_ERROR); + + err = U_ZERO_ERROR; + udat_parseCalendar(df, cal, u"2021-", -1, NULL, &err); + assertTrue("Success parsing '2021-'", err == U_PARSE_ERROR); + } + udat_close(df); + ucal_close(cal); +} + #endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/icu4j/main/classes/core/src/com/ibm/icu/text/SimpleDateFormat.java b/icu4j/main/classes/core/src/com/ibm/icu/text/SimpleDateFormat.java index 910f96afa45..1f3d25f0c15 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/text/SimpleDateFormat.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/text/SimpleDateFormat.java @@ -3787,6 +3787,9 @@ public class SimpleDateFormat extends DateFormat { } else { number = parseInt(text, pos, allowNegative,currentNumberFormat); } + if (!isLenient() && pos.getIndex() < start + count) { + return -start; + } if (number != null) { if (patternCharIndex != DateFormat.RELATED_YEAR) { cal.set(field, number.intValue()); diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/DateFormatTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/DateFormatTest.java index 3f25d642f01..27e42fa9dd7 100644 --- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/DateFormatTest.java +++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/DateFormatTest.java @@ -5610,4 +5610,20 @@ public class DateFormatTest extends TestFmwk { } } } + + @Test + public void testExtraneousCharacters() { + // regression test for ICU-21802 + Calendar cal = Calendar.getInstance(); + SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd", ULocale.US); + df.setLenient(false); + + ParsePosition pos = new ParsePosition(0); + df.parse("2021", cal, pos); + assertTrue("Success parsing '2021'", pos.getIndex() == 0); + + pos.setIndex(0); + df.parse("2021-", cal, pos); + assertTrue("Success parsing '2021-'", pos.getIndex() == 0); + } }