From 83085e97242166513be751c8c5099902aef2d7bc Mon Sep 17 00:00:00 2001 From: Adeel Kazmi Date: Thu, 6 May 2021 12:49:20 +0100 Subject: [PATCH] Fixed Signal crash on Ubuntu 20.04 Change-Id: I785ed3bf0142ba6adb4bbc3484a0e0a36a2b7f53 --- automated-tests/src/common/signal-helper.h | 15 ++++++++++- .../src/dali/utc-Dali-SignalTemplates.cpp | 22 +++++++++++---- dali/public-api/signals/base-signal.cpp | 6 +++++ dali/public-api/signals/base-signal.h | 31 +++++++++++++++++----- 4 files changed, 61 insertions(+), 13 deletions(-) diff --git a/automated-tests/src/common/signal-helper.h b/automated-tests/src/common/signal-helper.h index 84844cf..4084e28 100644 --- a/automated-tests/src/common/signal-helper.h +++ b/automated-tests/src/common/signal-helper.h @@ -2,7 +2,7 @@ #define SIGNAL_HELPER /* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * Copyright (c) 2021 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -720,6 +720,12 @@ public: signal.Connect(this, &TestEmitDuringCallback::DeleteSignalDuringEmit); } + void DeleteDuringEmitConnect(TestSignals::FloatRet0ParamSignal& signal) + { + mFloatRet0ParamSignal = &signal; + signal.Connect(this, &TestEmitDuringCallback::DeleteRetSignalDuringEmit); + } + void VoidSlotVoid() { // Emitting during Emit is very bad! @@ -733,6 +739,13 @@ public: delete mVoidSignalVoid; } + float DeleteRetSignalDuringEmit() + { + // deleting the signal during the emit + delete mFloatRet0ParamSignal; + return 0.0f; + } + float FloatRet0Param() { // Emitting during Emit is very bad! diff --git a/automated-tests/src/dali/utc-Dali-SignalTemplates.cpp b/automated-tests/src/dali/utc-Dali-SignalTemplates.cpp index d3a03fc..67299e2 100644 --- a/automated-tests/src/dali/utc-Dali-SignalTemplates.cpp +++ b/automated-tests/src/dali/utc-Dali-SignalTemplates.cpp @@ -1621,13 +1621,25 @@ int UtcDaliSignalDeleteDuringEmit(void) TestApplication application; // Create core for debug logging - TestSignals::VoidRetNoParamSignal* signal = new TestSignals::VoidRetNoParamSignal; + { + TestSignals::VoidRetNoParamSignal* signal = new TestSignals::VoidRetNoParamSignal; - TestEmitDuringCallback handler1; - handler1.DeleteDuringEmitConnect(*signal); + TestEmitDuringCallback handler1; + handler1.DeleteDuringEmitConnect(*signal); - // should just log an error - signal->Emit(); + // should just log an error + signal->Emit(); + } + + { + TestSignals::FloatRet0ParamSignal* signal = new TestSignals::FloatRet0ParamSignal; + + TestEmitDuringCallback handler1; + handler1.DeleteDuringEmitConnect(*signal); + + // should just log an error + signal->Emit(); + } tet_result(TET_PASS); diff --git a/dali/public-api/signals/base-signal.cpp b/dali/public-api/signals/base-signal.cpp index 9b24091..a8c55ad 100644 --- a/dali/public-api/signals/base-signal.cpp +++ b/dali/public-api/signals/base-signal.cpp @@ -43,6 +43,12 @@ BaseSignal::~BaseSignal() if(mEmittingFlag) { DALI_LOG_ERROR("Invalid destruction of Signal during Emit()\n"); + + // Set the signal deletion flag as well if set + if(mSignalDeleted) + { + *mSignalDeleted = true; + } } // The signal is being destroyed. We have to inform any slots diff --git a/dali/public-api/signals/base-signal.h b/dali/public-api/signals/base-signal.h index 1e42e0b..b63e1e2 100644 --- a/dali/public-api/signals/base-signal.h +++ b/dali/public-api/signals/base-signal.h @@ -169,6 +169,10 @@ public: return returnVal; } + // Guards against calling CleanupConnections if the signal is deleted during emission + bool signalDeleted{false}; + mSignalDeleted = &signalDeleted; + // If more connections are added by callbacks, these are ignore until the next Emit() // Note that count cannot be reduced while iterating const std::size_t initialCount(mSignalConnections.size()); @@ -185,8 +189,12 @@ public: } } - // Cleanup NULL values from Connection container - CleanupConnections(); + if(!signalDeleted) + { + // Cleanup NULL values from Connection container + CleanupConnections(); + mSignalDeleted = nullptr; + } return returnVal; } @@ -208,6 +216,10 @@ public: return; } + // Guards against calling CleanupConnections if the signal is deleted during emission + bool signalDeleted{false}; + mSignalDeleted = &signalDeleted; + // If more connections are added by callbacks, these are ignore until the next Emit() // Note that count cannot be reduced while iterating const std::size_t initialCount(mSignalConnections.size()); @@ -224,8 +236,12 @@ public: } } - // Cleanup NULL values from Connection container - CleanupConnections(); + if(!signalDeleted) + { + // Cleanup NULL values from Connection container + CleanupConnections(); + mSignalDeleted = nullptr; + } } // Connect / Disconnect function for use by Signal implementations @@ -313,9 +329,10 @@ private: BaseSignal& operator=(BaseSignal&&) = delete; ///< Deleted move assignment operator. @SINCE_1_9.25 private: - std::vector mSignalConnections; ///< Array of connections - uint32_t mNullConnections{0}; ///< Empty Connections in the array. - bool mEmittingFlag{false}; ///< Used to guard against nested Emit() calls + std::vector mSignalConnections; ///< Array of connections + uint32_t mNullConnections{0}; ///< Empty Connections in the array. + bool mEmittingFlag{false}; ///< Used to guard against nested Emit() calls. + bool* mSignalDeleted{nullptr}; ///< Used to guard against deletion during Emit() calls. }; /** -- 2.7.4