From d2a988512efcad7a72c6624f7015fc08271ae0a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Sat, 22 Jul 2017 16:41:44 +0200 Subject: macOS: Detect use of heap-allocated QMacAutoReleasePool QMacAutoReleasePool is backed by an NSAutoreleasePool, which documents that "you should always drain an autorelease pool in the same context (invocation of a method or function, or body of a loop) that it was created". This means allocating QMacAutoReleasePool on the heap is not a supported use-case, but unfortunately we can't detect it on construction time. Instead we detect whether or not the associated NSAutoreleasePool has been drained, and prevent a double-drain of the pool. Change-Id: Ifd7380a06152e9e742d2e199476ed3adab326d9c Reviewed-by: Simon Hausmann --- .../qmacautoreleasepool/qmacautoreleasepool.pro | 4 + .../qmacautoreleasepool/tst_qmacautoreleasepool.mm | 111 +++++++++++++++++++++ tests/auto/corelib/tools/tools.pro | 1 + 3 files changed, 116 insertions(+) create mode 100644 tests/auto/corelib/tools/qmacautoreleasepool/qmacautoreleasepool.pro create mode 100644 tests/auto/corelib/tools/qmacautoreleasepool/tst_qmacautoreleasepool.mm (limited to 'tests/auto/corelib/tools') diff --git a/tests/auto/corelib/tools/qmacautoreleasepool/qmacautoreleasepool.pro b/tests/auto/corelib/tools/qmacautoreleasepool/qmacautoreleasepool.pro new file mode 100644 index 0000000000..26b3a47472 --- /dev/null +++ b/tests/auto/corelib/tools/qmacautoreleasepool/qmacautoreleasepool.pro @@ -0,0 +1,4 @@ +CONFIG += testcase +TARGET = tst_qmacautoreleasepool +QT = core testlib +SOURCES = tst_qmacautoreleasepool.mm diff --git a/tests/auto/corelib/tools/qmacautoreleasepool/tst_qmacautoreleasepool.mm b/tests/auto/corelib/tools/qmacautoreleasepool/tst_qmacautoreleasepool.mm new file mode 100644 index 0000000000..8f1069f419 --- /dev/null +++ b/tests/auto/corelib/tools/qmacautoreleasepool/tst_qmacautoreleasepool.mm @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include + +class tst_QMacAutoreleasePool : public QObject +{ + Q_OBJECT +private slots: + void noPool(); + void rootLevelPool(); + void stackAllocatedPool(); + void heapAllocatedPool(); +}; + +static id lastDeallocedObject = nil; + +@interface DeallocTracker : NSObject @end +@implementation DeallocTracker +-(void)dealloc +{ + lastDeallocedObject = self; + [super dealloc]; +} +@end + +void tst_QMacAutoreleasePool::noPool() +{ + // No pool, will not be released, but should not crash + + [[[DeallocTracker alloc] init] autorelease]; +} + +void tst_QMacAutoreleasePool::rootLevelPool() +{ + // The root level case, no NSAutoreleasePool since we're not in the main + // runloop, and objects autoreleased as part of main. + + NSObject *allocedObject = nil; + { + QMacAutoReleasePool qtPool; + allocedObject = [[[DeallocTracker alloc] init] autorelease]; + } + QCOMPARE(lastDeallocedObject, allocedObject); +} + +void tst_QMacAutoreleasePool::stackAllocatedPool() +{ + // The normal case, other pools surrounding our pool, draining + // our pool before any other pool. + + NSObject *allocedObject = nil; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + { + QMacAutoReleasePool qtPool; + allocedObject = [[[DeallocTracker alloc] init] autorelease]; + } + QCOMPARE(lastDeallocedObject, allocedObject); + [pool drain]; +} + +void tst_QMacAutoreleasePool::heapAllocatedPool() +{ + // The special case, a pool allocated on the heap, or as a member of a + // heap allocated object. This is not a supported use of QMacAutoReleasePool, + // and will result in warnings if the pool is prematurely drained. + + NSObject *allocedObject = nil; + { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + QMacAutoReleasePool *qtPool = nullptr; + { + qtPool = new QMacAutoReleasePool; + allocedObject = [[[DeallocTracker alloc] init] autorelease]; + } + [pool drain]; + delete qtPool; + } + QCOMPARE(lastDeallocedObject, allocedObject); +} + +QTEST_APPLESS_MAIN(tst_QMacAutoreleasePool) + +#include "tst_qmacautoreleasepool.moc" diff --git a/tests/auto/corelib/tools/tools.pro b/tests/auto/corelib/tools/tools.pro index 6720307d59..f35ed026ac 100644 --- a/tests/auto/corelib/tools/tools.pro +++ b/tests/auto/corelib/tools/tools.pro @@ -67,3 +67,4 @@ SUBDIRS=\ qvector_strictiterators \ qversionnumber +darwin: SUBDIRS += qmacautoreleasepool -- cgit v1.2.3 From 3b61cd6ad738b8479bf216dcf736bb935e8812df Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Sun, 20 Aug 2017 14:22:44 -0700 Subject: QStringView: De-inline the length calculation so we can use SSE2 Performance is more important in this case than the theoretical benefit of constexpr. This commit implements the SSE2 search for 16-bit null and it might be possible to implement the equivalent for AArch64 (investigation required). It also adds a fallback to wcslen() for systems where wchar_t is short (non-x86 Windows or 32-bit x86 build with -no-sse2). We can re-add the constexpr loop once the C++ language has a way of overloading constexpr and non-constexpr. GCC has a non-standard way to do that with __builtin_constant_p, which is also implemented in this commit, but note that the inline function is still not constexpr. Change-Id: I6e9274c1e7444ad48c81fffd14dcaacafda5ebdc Reviewed-by: Oswald Buddenhagen Reviewed-by: Thiago Macieira --- .../corelib/tools/qstringview/tst_qstringview.cpp | 44 ++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'tests/auto/corelib/tools') diff --git a/tests/auto/corelib/tools/qstringview/tst_qstringview.cpp b/tests/auto/corelib/tools/qstringview/tst_qstringview.cpp index 9617afb651..48ea5a794c 100644 --- a/tests/auto/corelib/tools/qstringview/tst_qstringview.cpp +++ b/tests/auto/corelib/tools/qstringview/tst_qstringview.cpp @@ -136,6 +136,7 @@ class tst_QStringView : public QObject private Q_SLOTS: void constExpr() const; void basics() const; + void literals() const; void at() const; void fromQString() const; @@ -305,6 +306,12 @@ void tst_QStringView::constExpr() const Q_STATIC_ASSERT(!sv2.isNull()); Q_STATIC_ASSERT(!sv2.empty()); Q_STATIC_ASSERT(sv2.size() == 5); + + constexpr char16_t *null = nullptr; + constexpr QStringView sv3(null); + Q_STATIC_ASSERT(sv3.isNull()); + Q_STATIC_ASSERT(sv3.isEmpty()); + Q_STATIC_ASSERT(sv3.size() == 0); } #else // storage_type is wchar_t { @@ -328,6 +335,12 @@ void tst_QStringView::constExpr() const Q_STATIC_ASSERT(!sv2.isNull()); Q_STATIC_ASSERT(!sv2.empty()); Q_STATIC_ASSERT(sv2.size() == 5); + + constexpr wchar_t *null = nullptr; + constexpr QStringView sv3(null); + Q_STATIC_ASSERT(sv3.isNull()); + Q_STATIC_ASSERT(sv3.isEmpty()); + Q_STATIC_ASSERT(sv3.size() == 0); } #endif #endif @@ -348,6 +361,37 @@ void tst_QStringView::basics() const QVERIFY(!(sv2 != sv1)); } +void tst_QStringView::literals() const +{ +#if !defined(Q_OS_WIN) || defined(Q_COMPILER_UNICODE_STRINGS) + // the + ensures it's a pointer, not an array + QCOMPARE(QStringView(+u"Hello").size(), 5); + QStringView sv = u"Hello"; +#else // storage_type is wchar_t + // the + ensures it's a pointer, not an array + QCOMPARE(QStringView(+L"Hello").size(), 5); + QStringView sv = L"Hello"; +#endif + QCOMPARE(sv.size(), 5); + QVERIFY(!sv.empty()); + QVERIFY(!sv.isEmpty()); + QVERIFY(!sv.isNull()); + QCOMPARE(*sv.utf16(), 'H'); + QCOMPARE(sv[0], QLatin1Char('H')); + QCOMPARE(sv.at(0), QLatin1Char('H')); + QCOMPARE(sv.front(), QLatin1Char('H')); + QCOMPARE(sv.first(), QLatin1Char('H')); + QCOMPARE(sv[4], QLatin1Char('o')); + QCOMPARE(sv.at(4), QLatin1Char('o')); + QCOMPARE(sv.back(), QLatin1Char('o')); + QCOMPARE(sv.last(), QLatin1Char('o')); + + QStringView sv2(sv.utf16(), sv.utf16() + sv.size()); + QVERIFY(!sv2.isNull()); + QVERIFY(!sv2.empty()); + QCOMPARE(sv2.size(), 5); +} + void tst_QStringView::at() const { QString hello("Hello"); -- cgit v1.2.3