Don't rely on TLS to call QThread::finish on VxW

On VxWorks, its pthread implementation fails on call to
`pthead_setspecific` which is made by first `QObject` constructor during
`QThreadPrivate::finish()`. This causes call to `QThreadData::current`,
since `QObject` doesn't have parent, and since the pthread is already
removed, it tries to set `QThreadData` for current pthread key, which
crashes.

The aforementioned `QObject`'s instances are created in multiple places
during `QThreadPrivate::finish` method, first one in during call to
`qCDebug()`.

The sequence currently leading to call to `QThreadData::current` starts
with `qCDebug` call in `QThreadPrivate::finish`, which:
 - creates `QDebug` object, which
 - creates `Stream`, which
 - creates `QTextStream`, which
 - creates `QTextStreamPrivate`, which
 - creates `QDeviceClosedNotifier`, which
 - is a `QObject`, which
 - calls `QThreadData::current()` because its `parent` is nullptr.

Even ignoring debug print, next line calls
`QCoreApplication::sendPostedEvents` which calls `QThreadData::current`
directly.

Pick-to: 6.7
Task-number: QTBUG-115777
Change-Id: I4d405eebdff0c63c6cd66fba4eaa95c3818ceaea
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Michał Łoś 2024-05-15 16:41:13 +02:00
parent 0beaa63d4a
commit e82b79d382

View File

@ -282,9 +282,13 @@ void *QThreadPrivate::start(void *arg)
#ifdef PTHREAD_CANCEL_DISABLE #ifdef PTHREAD_CANCEL_DISABLE
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, nullptr); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, nullptr);
#endif #endif
#if !defined(Q_OS_QNX) #if !defined(Q_OS_QNX) && !defined(Q_OS_VXWORKS)
// On QNX, calling finish() from a thread_local destructor causes the C // On QNX, calling finish() from a thread_local destructor causes the C
// library to hang. // library to hang.
// On VxWorks, its pthread implementation fails on call to `pthead_setspecific` which is made
// by first QObject constructor during `finish()`. This causes call to QThread::current, since
// QObject doesn't have parent, and since the pthread is already removed, it tries to set
// QThreadData for current pthread key, which crashes.
static thread_local static thread_local
#endif #endif
auto cleanup = qScopeGuard([=] { finish(arg); }); auto cleanup = qScopeGuard([=] { finish(arg); });