diff options
author | Ievgenii Meshcheriakov <ievgenii.meshcheriakov@qt.io> | 2021-07-22 17:44:36 +0200 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2021-08-06 17:55:54 +0000 |
commit | a2fddbf05a1ba769f7e67d2e36ccad7b262a9950 (patch) | |
tree | a88fca0744c2be957ce0aed79e2f65689568bdcc | |
parent | 93345662b05359e0b895faf2be0f2358af08339b (diff) |
QCalendar: Delete registered calendar backends on program exit
Add code to check if the calendar registry is destroyed to all
QCalendar methods that dereference QCalendarBackend pointer.
Change-Id: I9b562355e2e0579396b52968f6065c6927cc9ca8
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
(cherry picked from commit 84a93d94ac8dfa3c962c0dda0ab19bbd80ac50ed)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r-- | src/corelib/time/qcalendar.cpp | 86 | ||||
-rw-r--r-- | src/corelib/time/qcalendar.h | 7 |
2 files changed, 76 insertions, 17 deletions
diff --git a/src/corelib/time/qcalendar.cpp b/src/corelib/time/qcalendar.cpp index c437adecac..8f545515fe 100644 --- a/src/corelib/time/qcalendar.cpp +++ b/src/corelib/time/qcalendar.cpp @@ -118,7 +118,12 @@ class QCalendarRegistry */ QAtomicPointer<const QCalendarBackend> gregorianCalendar = nullptr; - enum : int { Unpopulated, Populated }; + enum : int { + Unpopulated, // The standard backends may not yet be created + Populated, // All standard backends were created + IsBeingDestroyed, // The registry and the backends are being destroyed + }; + /* Fast way to check whether the standard calendars were populated. @@ -134,6 +139,10 @@ class QCalendarRegistry public: QCalendarRegistry() { byId.resize(int(QCalendar::System::Last) + 1); } + ~QCalendarRegistry(); + + bool isBeingDestroyed() const { return status.loadRelaxed() == IsBeingDestroyed; } + void registerCustomBackend(QCalendarBackend *backend, const QStringList &names); QStringList availableCalendars(); @@ -169,6 +178,21 @@ public: }; /*! + Destroy the registry. + + This destroys all registered backends. This destructor should only be called + in a single-threaded context at program exit. +*/ +QCalendarRegistry::~QCalendarRegistry() +{ + QWriteLocker locker(&lock); + + status.storeRelaxed(IsBeingDestroyed); + + qDeleteAll(byId); +} + +/*! Registers a custom backend. A new unique ID is allocated for the \a backend. The registry takes @@ -508,7 +532,7 @@ Q_GLOBAL_STATIC(QtPrivate::QCalendarRegistry, calendarRegistry); Destroys the calendar backend. Each calendar backend, once instantiated and successfully registered by ID, - shall exist for the lifetime of the program. Destroying a + shall exist until it is destroyed by the registry. Destroying a successfully-registered backend otherwise may leave existing QCalendar instances referencing the destroyed calendar, with undefined results. @@ -518,7 +542,8 @@ Q_GLOBAL_STATIC(QtPrivate::QCalendarRegistry, calendarRegistry); */ QCalendarBackend::~QCalendarBackend() { - Q_ASSERT(!m_id.isValid()); + Q_ASSERT(!m_id.isValid() || calendarRegistry.isDestroyed() + || calendarRegistry->isBeingDestroyed()); } /*! @@ -616,6 +641,15 @@ QCalendar::System QCalendarBackend::calendarSystem() const return m_id.isInEnum() ? QCalendar::System(m_id.index()) : QCalendar::System::User; } +/* + Create local variable d containing the backend associated with a QCalendar + instance unless the calendar registry is destroyed together with all backends, + then return nullptr. + + This assumes that the registry is only destroyed in single threaded context. +*/ +#define SAFE_D() const auto d = Q_UNLIKELY(calendarRegistry.isDestroyed()) ? nullptr : d_ptr + /*! The primary name of this calendar. @@ -625,6 +659,7 @@ QCalendar::System QCalendarBackend::calendarSystem() const */ QString QCalendar::name() const { + SAFE_D(); return d ? d->name() : QString(); } @@ -1141,17 +1176,16 @@ const QCalendarBackend *QCalendarBackend::gregorian() */ QCalendar::QCalendar() - : d(QCalendarBackend::gregorian()) + : d_ptr(QCalendarBackend::gregorian()) { - Q_ASSERT(!d || d->calendarId().isValid()); + Q_ASSERT(!d_ptr || d_ptr->calendarId().isValid()); } -QCalendar::QCalendar(QCalendar::System system) - : d(QCalendarBackend::fromEnum(system)) +QCalendar::QCalendar(QCalendar::System system) : d_ptr(QCalendarBackend::fromEnum(system)) { // If system is valid, we should get a valid d for that system. - Q_ASSERT(!d || (uint(system) > uint(QCalendar::System::Last)) - || (d->calendarId().index() == size_t(system))); + Q_ASSERT(!d_ptr || (uint(system) > uint(QCalendar::System::Last)) + || (d_ptr->calendarId().index() == size_t(system))); } /*! @@ -1166,21 +1200,21 @@ QCalendar::QCalendar(QCalendar::System system) registered by name. */ QCalendar::QCalendar(QCalendar::SystemId id) - : d(QCalendarBackend::fromId(id)) + : d_ptr(QCalendarBackend::fromId(id)) { - Q_ASSERT(!d || d->calendarId().index() == id.index()); + Q_ASSERT(!d_ptr || d_ptr->calendarId().index() == id.index()); } QCalendar::QCalendar(QLatin1String name) - : d(QCalendarBackend::fromName(name)) + : d_ptr(QCalendarBackend::fromName(name)) { - Q_ASSERT(!d || d->calendarId().isValid()); + Q_ASSERT(!d_ptr || d_ptr->calendarId().isValid()); } QCalendar::QCalendar(QStringView name) - : d(QCalendarBackend::fromName(name)) + : d_ptr(QCalendarBackend::fromName(name)) { - Q_ASSERT(!d || d->calendarId().isValid()); + Q_ASSERT(!d_ptr || d_ptr->calendarId().isValid()); } /*! @@ -1205,6 +1239,7 @@ QCalendar::QCalendar(QStringView name) */ int QCalendar::daysInMonth(int month, int year) const { + SAFE_D(); return d ? d->daysInMonth(month, year) : 0; } @@ -1215,6 +1250,7 @@ int QCalendar::daysInMonth(int month, int year) const */ int QCalendar::daysInYear(int year) const { + SAFE_D(); return d ? d->daysInYear(year) : 0; } @@ -1228,6 +1264,7 @@ int QCalendar::daysInYear(int year) const */ int QCalendar::monthsInYear(int year) const { + SAFE_D(); return d ? year == Unspecified ? d->maximumMonthsInYear() : d->monthsInYear(year) : 0; } @@ -1241,6 +1278,7 @@ int QCalendar::monthsInYear(int year) const */ bool QCalendar::isDateValid(int year, int month, int day) const { + SAFE_D(); return d && d->isDateValid(year, month, day); } @@ -1252,6 +1290,7 @@ bool QCalendar::isDateValid(int year, int month, int day) const */ bool QCalendar::isGregorian() const { + SAFE_D(); return d && d->isGregorian(); } @@ -1266,6 +1305,7 @@ bool QCalendar::isGregorian() const */ bool QCalendar::isLeapYear(int year) const { + SAFE_D(); return d && d->isLeapYear(year); } @@ -1276,6 +1316,7 @@ bool QCalendar::isLeapYear(int year) const */ bool QCalendar::isLunar() const { + SAFE_D(); return d && d->isLunar(); } @@ -1288,6 +1329,7 @@ bool QCalendar::isLunar() const */ bool QCalendar::isLuniSolar() const { + SAFE_D(); return d && d->isLuniSolar(); } @@ -1299,6 +1341,7 @@ bool QCalendar::isLuniSolar() const */ bool QCalendar::isSolar() const { + SAFE_D(); return d && d->isSolar(); } @@ -1313,6 +1356,7 @@ bool QCalendar::isSolar() const */ bool QCalendar::isProleptic() const { + SAFE_D(); return d && d->isProleptic(); } @@ -1343,6 +1387,7 @@ bool QCalendar::isProleptic() const */ bool QCalendar::hasYearZero() const { + SAFE_D(); return d && d->hasYearZero(); } @@ -1353,6 +1398,7 @@ bool QCalendar::hasYearZero() const */ int QCalendar::maximumDaysInMonth() const { + SAFE_D(); return d ? d->maximumDaysInMonth() : 0; } @@ -1363,6 +1409,7 @@ int QCalendar::maximumDaysInMonth() const */ int QCalendar::minimumDaysInMonth() const { + SAFE_D(); return d ? d->minimumDaysInMonth() : 0; } @@ -1373,6 +1420,7 @@ int QCalendar::minimumDaysInMonth() const */ int QCalendar::maximumMonthsInYear() const { + SAFE_D(); return d ? d->maximumMonthsInYear() : 0; } @@ -1394,6 +1442,7 @@ int QCalendar::maximumMonthsInYear() const */ QDate QCalendar::dateFromParts(int year, int month, int day) const { + SAFE_D(); qint64 jd; return d && d->dateToJulianDay(year, month, day, &jd) ? QDate::fromJulianDay(jd) : QDate(); @@ -1415,6 +1464,7 @@ QDate QCalendar::dateFromParts(const QCalendar::YearMonthDay &parts) const */ QCalendar::YearMonthDay QCalendar::partsFromDate(QDate date) const { + SAFE_D(); return d && date.isValid() ? d->julianDayToDate(date.toJulianDay()) : YearMonthDay(); } @@ -1429,6 +1479,7 @@ QCalendar::YearMonthDay QCalendar::partsFromDate(QDate date) const */ int QCalendar::dayOfWeek(QDate date) const { + SAFE_D(); return d && date.isValid() ? d->dayOfWeek(date.toJulianDay()) : 0; } @@ -1456,6 +1507,7 @@ int QCalendar::dayOfWeek(QDate date) const QString QCalendar::monthName(const QLocale &locale, int month, int year, QLocale::FormatType format) const { + SAFE_D(); const int maxMonth = year == Unspecified ? maximumMonthsInYear() : monthsInYear(year); if (!d || month < 1 || month > maxMonth) return QString(); @@ -1485,6 +1537,7 @@ QString QCalendar::monthName(const QLocale &locale, int month, int year, QString QCalendar::standaloneMonthName(const QLocale &locale, int month, int year, QLocale::FormatType format) const { + SAFE_D(); const int maxMonth = year == Unspecified ? maximumMonthsInYear() : monthsInYear(year); if (!d || month < 1 || month > maxMonth) return QString(); @@ -1509,6 +1562,7 @@ QString QCalendar::standaloneMonthName(const QLocale &locale, int month, int yea QString QCalendar::weekDayName(const QLocale &locale, int day, QLocale::FormatType format) const { + SAFE_D(); return d ? d->weekDayName(locale, day, format) : QString(); } @@ -1531,6 +1585,7 @@ QString QCalendar::weekDayName(const QLocale &locale, int day, QString QCalendar::standaloneWeekDayName(const QLocale &locale, int day, QLocale::FormatType format) const { + SAFE_D(); return d ? d->standaloneWeekDayName(locale, day, format) : QString(); } @@ -1557,6 +1612,7 @@ QString QCalendar::dateTimeToString(QStringView format, const QDateTime &datetim QDate dateOnly, QTime timeOnly, const QLocale &locale) const { + SAFE_D(); return d ? d->dateTimeToString(format, datetime, dateOnly, timeOnly, locale) : QString(); } diff --git a/src/corelib/time/qcalendar.h b/src/corelib/time/qcalendar.h index aedbae94fb..3238fff7d8 100644 --- a/src/corelib/time/qcalendar.h +++ b/src/corelib/time/qcalendar.h @@ -153,7 +153,7 @@ public: explicit QCalendar(SystemId id); // QCalendar is a trivially copyable value type. - bool isValid() const { return d != nullptr; } + bool isValid() const { return d_ptr != nullptr; } // Date queries: int daysInMonth(int month, int year = Unspecified) const; @@ -201,7 +201,10 @@ public: static QStringList availableCalendars(); private: // Always supplied by QCalendarBackend and expected to be a singleton - const QCalendarBackend *d; + // Note that the calendar registry destroys all backends when it is itself + // destroyed. The code should check if the registry is destroyed before + // dereferencing this pointer. + const QCalendarBackend *d_ptr; }; QT_END_NAMESPACE |