From d1210281e41008ce2e3510aa5cfb3ebea1c57734 Mon Sep 17 00:00:00 2001 From: Ihor Dutchak Date: Mon, 17 Apr 2017 00:35:38 +0300 Subject: Fix undefined behavior in QSharedPointer::create() Initialize a deleter for a new object, created by QSharedPointer::create(), only after the object is actually constructed. [ChangeLog][QtCore][QSharedPointer] Fixed undefined behavior when creating an object with QSharedPointer::create() and its conscructor throws an exception. Task-number: QTBUG-49824 Change-Id: I07f77a78ff468d9b45b8ef133278e8cdd96a0647 Reviewed-by: Olivier Goffart (Woboq GmbH) --- .../tools/qsharedpointer/tst_qsharedpointer.cpp | 50 ++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'tests/auto/corelib/tools') diff --git a/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp b/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp index d0a0feb125..7850478602 100644 --- a/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp +++ b/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp @@ -97,6 +97,8 @@ private slots: void qvariantCast(); void sharedFromThis(); + void constructorThrow(); + void threadStressTest_data(); void threadStressTest(); void validConstructs(); @@ -2594,6 +2596,54 @@ void tst_QSharedPointer::sharedFromThis() QCOMPARE(Data::destructorCounter, destructions + 6); } +#ifndef QT_NO_EXCEPTIONS +class ThrowData: public Data +{ +public: + static int childDestructorCounter; + static int childGenerationCounter; + + ThrowData() + { + childGenerationCounter++; + throw QStringLiteral("Dummy exception"); + } + + ~ThrowData() + { + childDestructorCounter++; + } +}; +int ThrowData::childDestructorCounter = 0; +int ThrowData::childGenerationCounter = 0; +#endif // !QT_NO_EXCEPTIONS + +void tst_QSharedPointer::constructorThrow() +{ +#ifndef QT_NO_EXCEPTIONS + int generation = Data::generationCounter; + int destructorCounter = Data::destructorCounter; + + int childGeneration = ThrowData::childGenerationCounter; + int childDestructorCounter = ThrowData::childDestructorCounter; + + QSharedPointer ptr; + QVERIFY_EXCEPTION_THROWN(ptr = QSharedPointer::create(), QString); + QVERIFY(ptr.isNull()); + QCOMPARE(ThrowData::childGenerationCounter, childGeneration + 1); + // destructor should never be called, if a constructor throws + // an exception + QCOMPARE(ThrowData::childDestructorCounter, childDestructorCounter); + + QCOMPARE(Data::generationCounter, generation + 1); + // but base class constructor doesn't throw, so base class destructor + // should be called + QCOMPARE(Data::destructorCounter, destructorCounter + 1); +#else + QSKIP("Needs exceptions"); +#endif // !QT_NO_EXCEPTIONS +} + namespace ReentrancyWhileDestructing { struct IB { -- cgit v1.2.3