diff options
Diffstat (limited to 'src/corelib/kernel/qcore_mac_objc.mm')
-rw-r--r-- | src/corelib/kernel/qcore_mac_objc.mm | 66 |
1 files changed, 65 insertions, 1 deletions
diff --git a/src/corelib/kernel/qcore_mac_objc.mm b/src/corelib/kernel/qcore_mac_objc.mm index db7e55f4b1..24d73fa8be 100644 --- a/src/corelib/kernel/qcore_mac_objc.mm +++ b/src/corelib/kernel/qcore_mac_objc.mm @@ -84,18 +84,82 @@ QT_FOR_EACH_MUTABLE_CORE_GRAPHICS_TYPE(QT_DECLARE_WEAK_QDEBUG_OPERATOR_FOR_CF_TY // ------------------------------------------------------------------------- +QT_END_NAMESPACE +QT_USE_NAMESPACE +@interface QT_MANGLE_NAMESPACE(QMacAutoReleasePoolTracker) : NSObject +{ + NSAutoreleasePool **m_pool; +} +-(id)initWithPool:(NSAutoreleasePool**)pool; +@end +@implementation QT_MANGLE_NAMESPACE(QMacAutoReleasePoolTracker) +-(id)initWithPool:(NSAutoreleasePool**)pool +{ + if (self = [super init]) + m_pool = pool; + return self; +} +-(void)dealloc +{ + if (*m_pool) { + // The pool is still valid, which means we're not being drained from + // the corresponding QMacAutoReleasePool (see below). + + // QMacAutoReleasePool has only a single member, the NSAutoreleasePool* + // so the address of that member is also the QMacAutoReleasePool itself. + QMacAutoReleasePool *pool = reinterpret_cast<QMacAutoReleasePool *>(m_pool); + qWarning() << "Premature drain of" << pool << "This can happen if you've allocated" + << "the pool on the heap, or as a member of a heap-allocated object. This is not a" + << "supported use of QMacAutoReleasePool, and might result in crashes when objects" + << "in the pool are deallocated and then used later on under the assumption they" + << "will be valid until" << pool << "has been drained."; + + // Reset the pool so that it's not drained again later on + *m_pool = nullptr; + } + + [super dealloc]; +} +@end +QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAutoReleasePoolTracker); +QT_BEGIN_NAMESPACE + QMacAutoReleasePool::QMacAutoReleasePool() : pool([[NSAutoreleasePool alloc] init]) { + [[[QMacAutoReleasePoolTracker alloc] initWithPool: + reinterpret_cast<NSAutoreleasePool **>(&pool)] autorelease]; } QMacAutoReleasePool::~QMacAutoReleasePool() { + if (!pool) { + qWarning() << "Prematurely drained pool" << this << "finally drained. Any objects belonging" + << "to this pool have already been released, and have potentially been invalid since the" + << "premature drain earlier on."; + return; + } + + // Save and reset pool before draining, so that the pool tracker can know + // that it's being drained by its owning pool. + NSAutoreleasePool *savedPool = static_cast<NSAutoreleasePool*>(pool); + pool = nullptr; + // Drain behaves the same as release, with the advantage that // if we're ever used in a garbage-collected environment, the // drain acts as a hint to the garbage collector to collect. - [static_cast<NSAutoreleasePool*>(pool) drain]; + [savedPool drain]; +} + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug debug, const QMacAutoReleasePool *pool) +{ + QDebugStateSaver saver(debug); + debug.nospace(); + debug << "QMacAutoReleasePool(" << (const void *)pool << ')'; + return debug; } +#endif // !QT_NO_DEBUG_STREAM #ifdef Q_OS_MACOS /* |