Error is swallowed in DateFormatSymbols::initializeData() function and lead to crash in UnicodeString::copyFrom

Description

I met a crash issue recently in UnicodeString &
UnicodeString::copyFrom(const UnicodeString &src, UBool fastCopy) Line 504
the crash happened because src is a null pointer.
****************************
// is the right side bogus?
if(src.isBogus()) {
setToBogus();
return *this;
}
****************************
The root cause is that previously in DateFormatSymbols::initializeData() function, when initiating fNarrowWeekdays, server met memory allocate error. The error is record in narrowWeeksEC but not status. As a result, fNarrowWeekdays is kept to be a nullptr but the error is swallowed. The creation process keeps going on and later in DateFormatSymbols::copyData(const DateFormatSymbols& other) when we tries to copy fNarrowWeekdays, it crashed.
*****************************
in DateFormatSymbols::initializeData():
// Format narrow weekdays -> fNarrowWeekdays
UErrorCode narrowWeeksEC = status;
initField(&fNarrowWeekdays, fNarrowWeekdaysCount, calendarSink, buildResourcePath(path, gDayNamesTag, gNamesFormatTag, gNamesNarrowTag, status), 1, narrowWeeksEC);
*****************************
in DateFormatSymbols::copyData(const DateFormatSymbols& other):
assignArray(fNarrowWeekdays, fNarrowWeekdaysCount, other.fNarrowWeekdays, other.fNarrowWeekdaysCount);
*****************************
Solution:
1. In DateFormatSymbols::initializeData() function, the error when initiating fNarrowWeekdays shouldn't be swallowed.
2. In UnicodeString::copyFrom() function, check whether src is null pointer

Activity

Show:

Peter Edberg 
March 17, 2023 at 4:49 AM

So it is not true that the error status in narrowWeeksEC is ignored. Ever since the changes for https://unicode-org.atlassian.net/browse/ICU-12614 in ICU 58.1, the DateFormatSymbols code for initializing fNarrowWeekdays and fStandaloneNarrowWeekdays has looked like this:

// Format narrow weekdays -> fNarrowWeekdays UErrorCode narrowWeeksEC = status; initField(&fNarrowWeekdays, fNarrowWeekdaysCount, calendarSink, buildResourcePath(path, gDayNamesTag, gNamesFormatTag, gNamesNarrowTag, status), 1, narrowWeeksEC); // Stand-alone narrow weekdays -> fStandaloneNarrowWeekdays UErrorCode standaloneNarrowWeeksEC = status; initField(&fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount, calendarSink, buildResourcePath(path, gDayNamesTag, gNamesStandaloneTag, gNamesNarrowTag, status), 1, standaloneNarrowWeeksEC); if (narrowWeeksEC == U_MISSING_RESOURCE_ERROR && standaloneNarrowWeeksEC != U_MISSING_RESOURCE_ERROR) { // If format/narrow not available, use standalone/narrow assignArray(fNarrowWeekdays, fNarrowWeekdaysCount, fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount); } else if (narrowWeeksEC != U_MISSING_RESOURCE_ERROR && standaloneNarrowWeeksEC == U_MISSING_RESOURCE_ERROR) { // If standalone/narrow not available, use format/narrow assignArray(fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount, fNarrowWeekdays, fNarrowWeekdaysCount); } else if (narrowWeeksEC == U_MISSING_RESOURCE_ERROR && standaloneNarrowWeeksEC == U_MISSING_RESOURCE_ERROR ) { // If neither is available, use format/abbreviated assignArray(fNarrowWeekdays, fNarrowWeekdaysCount, fShortWeekdays, fShortWeekdaysCount); assignArray(fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount, fShortWeekdays, fShortWeekdaysCount); }

So if there is an error initializing fNarrowWeekdays it tries to fill them in from fStandaloneNarrowWeekdays (if there was no error for those), and vice versa. If there was an error for both, it fills them in instead from fShortWeekdays. And if there was an error initializing fShortWeekdays, that would have affected the overall status; from earlier code:

// Format abbreviated weekdays -> fShortWeekdays initField(&fShortWeekdays, fShortWeekdaysCount, calendarSink, buildResourcePath(path, gDayNamesTag, gNamesFormatTag, gNamesAbbrTag, status), 1, status);

However, it was still the case that the DateFormatSymbols::assignArray method, used above but also in the DateFormatSymbols::copyData method used to implement operator=, did not check whether its srcArray parameter was nullptr. I have added a check for that (so in that case, assignArray will return with dstArray=nullptr and dstCount=0).

This brings up the question: Will this just defer a crash to later clients of DateFormatSymbols (really just SimpleDateFormat) when they encounter a nullptr for some fXxxxx field in DateFormatSymbols?

In SimpleDateFormat, those fields are all handled by _appendSymbol, which currently has

U_ASSERT(0 <= value && value < symbolsCount);

So any cases in which _appendSymbol attempts to process DateFormatSymbols entry with fXxxxx = nullptr and fXxxxxCount = 0 will produce an assert, and we will learn about it. This is better than a crash with no explanation in DateFormatSymbols.

Fixed

Details

Assignee

Reporter

Components

Reviewer

Priority

Fix versions

Created March 10, 2022 at 10:53 AM
Updated March 17, 2023 at 4:12 PM
Resolved March 17, 2023 at 4:12 PM