Issue 133 race in proxy destruct (#177)

* fix construct/destruct order of mutex/data in AsnycCalls

Destroying a mutex which might still be owned leads to undefined behaviour.
It wasn't the case here but using the right order is more resistant to future bugs.

* proxy AsnycCalls: don't leave map in unspecified state

* fix 133: use thread-safe container for proxy interfaces list

* proxy callback payload uses concrete signalData

* proxy: revert adding the wrapper class InterfaceContainer

It's no longer required and simplifies the locking logic.

* Proxy: avoid additional lambda wrapper around signal callbacks

As proposed in
https://github.com/Kistler-Group/sdbus-cpp/pull/177#issuecomment-834439707
option 3.

Still TODO: Avoid relying on std::map's non-invalidatable by adding just
std::unique_ptr<Proxy::InterfaceData::SignalData> to the container.

* proxy: add missing underscore prefix

* proxy: put InterfaceData::SignalData into a unique_ptr

This ways, we avoid relying on std::map's non-invalidatable references.

* proxy: code style: get raw pointer directly

* style: fix code style

Co-authored-by: Stanislav Angelovic <stanislav.angelovic@siemens.com>
This commit is contained in:
Urs Ritzmann
2021-06-03 18:53:38 +02:00
committed by GitHub
co-authored by Stanislav Angelovic
parent 118faa58f6
commit fa9569fdd9
2 changed files with 29 additions and 23 deletions
+15 -4
View File
@@ -98,10 +98,20 @@ namespace sdbus::internal {
using SignalName = std::string;
struct SignalData
{
signal_handler callback_;
SlotPtr slot_;
SignalData(Proxy& proxy, signal_handler callback, SlotPtr slot)
: proxy(proxy)
, callback(std::move(callback))
, slot(std::move(slot))
{}
Proxy& proxy;
signal_handler callback;
// slot_ must be listed after callback_ to ensure that slot_ is destructed first.
// Destructing the slot_ will sd_bus_slot_unref() the callback.
// Only after sd_bus_slot_unref(), we can safely delete the callback. The bus mutex (SdBus::sdbusMutex_)
// ensures that sd_bus_slot_unref() and the callback execute sequentially.
SlotPtr slot;
};
std::map<SignalName, SignalData> signals_;
std::map<SignalName, std::unique_ptr<SignalData>> signals_;
};
std::map<InterfaceName, InterfaceData> interfaces_;
@@ -150,6 +160,7 @@ namespace sdbus::internal {
{
std::unique_lock lock(mutex_);
auto asyncCallSlots = std::move(calls_);
calls_ = {};
lock.unlock();
// Releasing call slot pointer acquires global sd-bus mutex. We have to perform the release
@@ -159,8 +170,8 @@ namespace sdbus::internal {
}
private:
std::unordered_map<void*, std::shared_ptr<CallData>> calls_;
std::mutex mutex_;
std::unordered_map<void*, std::shared_ptr<CallData>> calls_;
} pendingAsyncCalls_;
};