From 73d6c2058fcb23ec9d126b7f862cf588d31222af Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 26 Jun 2020 09:50:09 -0700 Subject: QSharedPointer: do allow calling deleters on null pointers I don't know why std::shared_ptr allows this, but why not. [ChangeLog][Important Behavior Changes] QSharedPointer objects will now call custom deleters even when the pointer being tracked was null. This behavior is the same as std::shared_ptr. Fixes: QTBUG-85285 Change-Id: I24006db8360041f598c5fffd161c260df0313b55 Reviewed-by: Giuseppe D'Angelo (cherry picked from commit 95afe6b244dbd9623a92399d1bed0b9f52aa1e65) Reviewed-by: Qt Cherry-pick Bot --- src/corelib/tools/qsharedpointer.cpp | 11 ++++++-- src/corelib/tools/qsharedpointer_impl.h | 15 ++++------ .../tools/qsharedpointer/tst_qsharedpointer.cpp | 33 ++++++++++++++++++++-- 3 files changed, 46 insertions(+), 13 deletions(-) diff --git a/src/corelib/tools/qsharedpointer.cpp b/src/corelib/tools/qsharedpointer.cpp index 0576fb2bd0..a24b689181 100644 --- a/src/corelib/tools/qsharedpointer.cpp +++ b/src/corelib/tools/qsharedpointer.cpp @@ -1,7 +1,8 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2016 Intel Corporation. +** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2020 Intel Corporation. +** Copyright (C) 2019 Klarälvdalens Datakonsult AB. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -1562,6 +1563,12 @@ void QtSharedPointer::internalSafetyCheckAdd(const void *d_ptr, const volatile v if (!kp) return; // end-game: the application is being destroyed already + if (!ptr) { + // nullptr is allowed to be tracked by more than one QSharedPointer, so we + // need something else to put in our tracking structures + ptr = d_ptr; + } + QMutexLocker lock(&kp->mutex); Q_ASSERT(!kp->dPointers.contains(d_ptr)); diff --git a/src/corelib/tools/qsharedpointer_impl.h b/src/corelib/tools/qsharedpointer_impl.h index 362d57fb9a..790c187cb9 100644 --- a/src/corelib/tools/qsharedpointer_impl.h +++ b/src/corelib/tools/qsharedpointer_impl.h @@ -1,7 +1,8 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2016 Intel Corporation. +** Copyright (C) 2019 The Qt Company Ltd. +** Copyright (C) 2020 Intel Corporation. +** Copyright (C) 2019 Klarälvdalens Datakonsult AB. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -107,7 +108,7 @@ namespace QtSharedPointer { template inline void executeDeleter(T *t, RetVal (Klass:: *memberDeleter)()) - { (t->*memberDeleter)(); } + { if (t) (t->*memberDeleter)(); } template inline void executeDeleter(T *t, Deleter d) { d(t); } @@ -319,7 +320,8 @@ public: { internalConstruct(ptr, deleter); } template - QSharedPointer(std::nullptr_t, Deleter) : value(nullptr), d(nullptr) { } + QSharedPointer(std::nullptr_t, Deleter deleter) : value(nullptr) + { internalConstruct(static_cast(nullptr), deleter); } QSharedPointer(const QSharedPointer &other) noexcept : value(other.value), d(other.d) { if (d) ref(); } @@ -470,11 +472,6 @@ private: template inline void internalConstruct(X *ptr, Deleter deleter) { - if (!ptr) { - d = nullptr; - return; - } - typedef QtSharedPointer::ExternalRefCountWithCustomDeleter Private; # ifdef QT_SHAREDPOINTER_TRACK_POINTERS typename Private::DestroyerFn actualDeleter = &Private::safetyCheckDeleter; diff --git a/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp b/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp index a9fd282ac9..9dd9f114f9 100644 --- a/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp +++ b/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp @@ -1,7 +1,8 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2016 Intel Corporation. +** Copyright (C) 2019 The Qt Company Ltd. +** Copyright (C) 2020 Intel Corporation. +** Copyright (C) 2019 Klarälvdalens Datakonsult AB. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. @@ -95,6 +96,7 @@ private slots: void constCorrectness(); void customDeleter(); void lambdaCustomDeleter(); + void customDeleterOnNullptr(); void creating(); void creatingCvQualified(); void creatingVariadic(); @@ -1846,6 +1848,33 @@ void tst_QSharedPointer::lambdaCustomDeleter() safetyCheck(); } +void tst_QSharedPointer::customDeleterOnNullptr() +{ + Data *null = nullptr; + int callCount = 0; + auto deleter = [&callCount](Data *) { ++callCount; }; + { + QSharedPointer ptr(null, deleter); + } + safetyCheck(); + QCOMPARE(callCount, 1); + + callCount = 0; + { + QSharedPointer ptr(nullptr, deleter); + } + safetyCheck(); + QCOMPARE(callCount, 1); + + callCount = 0; + { + QSharedPointer ptr1(null, deleter); + QSharedPointer ptr2(nullptr, deleter); + } + safetyCheck(); + QCOMPARE(callCount, 2); +} + void customQObjectDeleterFn(QObject *obj) { ++customDeleterFnCallCount; -- cgit v1.2.3