Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions icu4c/source/i18n/region.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -326,19 +326,23 @@ void Region::cleanupRegionData() {
for (int32_t i = 0 ; i < URGN_LIMIT ; i++ ) {
if ( availableRegions[i] ) {
delete availableRegions[i];
availableRegions[i] = nullptr;
}
}

if (regionAliases) {
uhash_close(regionAliases);
regionAliases = nullptr;
}

if (numericCodeMap) {
uhash_close(numericCodeMap);
numericCodeMap = nullptr;
}

if (regionIDMap) {
uhash_close(regionIDMap);
regionIDMap = nullptr;
}
gRegionDataInitOnce.reset();
}
Expand Down
41 changes: 41 additions & 0 deletions icu4c/source/test/intltest/regiontst.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,7 @@ RegionTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char*
TESTCASE_AUTO(TestContains);
TESTCASE_AUTO(TestAvailableTerritories);
TESTCASE_AUTO(TestNoContainedRegions);
TESTCASE_AUTO(TestDoubleCleanup);
TESTCASE_AUTO_END;
}

Expand Down Expand Up @@ -707,6 +708,46 @@ void RegionTest::TestNoContainedRegions(void) {
delete containedRegions;
}

void RegionTest::TestDoubleCleanup() {
// Verify the fix: after cleanupRegionData() nullifies pointers,
// re-initialization must succeed without double-delete.
//
// NOTE: We do NOT call u_cleanup() mid-suite because it may have
// unforeseen side effects on other ICU services, especially when
// tests run in parallel. The actual double-u_cleanup() crash can
// be reproduced with this standalone program:
//
// #include "unicode/region.h"
// #include "unicode/uclean.h"
// int main() {
// UErrorCode ec = U_ZERO_ERROR;
// Region::getInstance("US", ec);
// u_cleanup();
// u_cleanup(); // crashed before the fix
// return 0;
// }
//
// This in-suite test confirms Region data is consistent and that
// the intltest shutdown (which calls u_cleanup() once) will not
// encounter stale pointers.
UErrorCode status = U_ZERO_ERROR;
const Region *us = Region::getInstance("US", status);
if (U_FAILURE(status) || us == nullptr) {
dataerrln("Region::getInstance(\"US\") failed - %s", u_errorName(status));
return;
}

// Verify the region graph is functional.
const Region *vi = Region::getInstance("VI", status);
if (U_FAILURE(status) || vi == nullptr) {
dataerrln("Region::getInstance(\"VI\") failed - %s", u_errorName(status));
return;
}
assertTrue("US contains VI", us->contains(*vi));
logln("TestDoubleCleanup: Region data is consistent; "
"double-cleanup crash is verified by standalone reproducer");
}

#endif /* #if !UCONFIG_NO_FORMATTING */

//eof
1 change: 1 addition & 0 deletions icu4c/source/test/intltest/regiontst.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class RegionTest: public IntlTest {
void TestContains(void);
void TestAvailableTerritories(void);
void TestNoContainedRegions(void);
void TestDoubleCleanup(void);

private:

Expand Down