Fix icu::OlsonTimeZone::getHistoricalOffset crash
The icu::TimeZone::adoptDefault may delete a old default timezone
while anther thread is calling the clone() to that old default timezone
in the createDefault running on another thread. Need to protect the
delete and DEFAULT_ZONE->clone() running concurrently. Otherwise, the
returned cloned TimeZone could contains partially trashed data and
cause crash later on.
test in https://chromium-review.googlesource.com/c/v8/v8/+/1601370
Upstream bug: https://unicode-org.atlassian.net/browse/ICU-20595
upstream PR: https://github.com/unicode-org/icu/pull/649/
Bug: chromium:950851
Test: v8 unittests - DateCache:AdoptDefault*
Change-Id: Ic8a1c374f20a50f5ebd567df8d34a65987315a7e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/deps/icu/+/1602037
Reviewed-by: Jungshik Shin <jshin@chromium.org>
diff --git a/README.chromium b/README.chromium
index 1d82edc..c75f49a 100644
--- a/README.chromium
+++ b/README.chromium
@@ -258,3 +258,10 @@
https://unicode-org.atlassian.net/browse/ICU-20391
- upstream PR:
https://github.com/unicode-org/icu/pull/628
+
+9. Timezone breakage patch
+ - patches/timezone.patch
+ - upstream bug:
+ https://unicode-org.atlassian.net/browse/ICU-20595
+ - upstream PR:
+ https://github.com/unicode-org/icu/pull/649
diff --git a/patches/timezone.patch b/patches/timezone.patch
new file mode 100644
index 0000000..d456d6f
--- /dev/null
+++ b/patches/timezone.patch
@@ -0,0 +1,51 @@
+diff --git a/source/i18n/timezone.cpp b/source/i18n/timezone.cpp
+index f129d8b6..f7b48273 100644
+--- a/source/i18n/timezone.cpp
++++ b/source/i18n/timezone.cpp
+@@ -527,6 +527,11 @@ TimeZone::detectHostTimeZone()
+
+ // -------------------------------------
+
++static UMutex *gMutex() {
++ static UMutex* m = new UMutex();
++ return m;
++}
++
+ /**
+ * Initialize DEFAULT_ZONE from the system default time zone.
+ * Upon return, DEFAULT_ZONE will not be NULL, unless operator new()
+@@ -536,6 +541,7 @@ static void U_CALLCONV initDefault()
+ {
+ ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
+
++ Mutex lock(gMutex());
+ // If setDefault() has already been called we can skip getting the
+ // default zone information from the system.
+ if (DEFAULT_ZONE != NULL) {
+@@ -571,7 +577,11 @@ TimeZone* U_EXPORT2
+ TimeZone::createDefault()
+ {
+ umtx_initOnce(gDefaultZoneInitOnce, initDefault);
+- return (DEFAULT_ZONE != NULL) ? DEFAULT_ZONE->clone() : NULL;
++ if (DEFAULT_ZONE == NULL) return NULL;
++ {
++ Mutex lock(gMutex());
++ return DEFAULT_ZONE->clone();
++ }
+ }
+
+ // -------------------------------------
+@@ -582,8 +592,11 @@ TimeZone::adoptDefault(TimeZone* zone)
+ if (zone != NULL)
+ {
+ TimeZone *old = DEFAULT_ZONE;
+- DEFAULT_ZONE = zone;
+- delete old;
++ {
++ Mutex lock(gMutex());
++ DEFAULT_ZONE = zone;
++ delete old;
++ }
+ ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
+ }
+ }
diff --git a/source/i18n/timezone.cpp b/source/i18n/timezone.cpp
index f129d8b..f7b4827 100644
--- a/source/i18n/timezone.cpp
+++ b/source/i18n/timezone.cpp
@@ -527,6 +527,11 @@
// -------------------------------------
+static UMutex *gMutex() {
+ static UMutex* m = new UMutex();
+ return m;
+}
+
/**
* Initialize DEFAULT_ZONE from the system default time zone.
* Upon return, DEFAULT_ZONE will not be NULL, unless operator new()
@@ -536,6 +541,7 @@
{
ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
+ Mutex lock(gMutex());
// If setDefault() has already been called we can skip getting the
// default zone information from the system.
if (DEFAULT_ZONE != NULL) {
@@ -571,7 +577,11 @@
TimeZone::createDefault()
{
umtx_initOnce(gDefaultZoneInitOnce, initDefault);
- return (DEFAULT_ZONE != NULL) ? DEFAULT_ZONE->clone() : NULL;
+ if (DEFAULT_ZONE == NULL) return NULL;
+ {
+ Mutex lock(gMutex());
+ return DEFAULT_ZONE->clone();
+ }
}
// -------------------------------------
@@ -582,8 +592,11 @@
if (zone != NULL)
{
TimeZone *old = DEFAULT_ZONE;
- DEFAULT_ZONE = zone;
- delete old;
+ {
+ Mutex lock(gMutex());
+ DEFAULT_ZONE = zone;
+ delete old;
+ }
ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
}
}