From d50a15b2a2a64e19d49951c7f601e8e8bd6dd071 Mon Sep 17 00:00:00 2001 From: sangelovic Date: Sun, 10 Nov 2019 17:31:58 +0100 Subject: [PATCH] Move C++17 uncaught_exceptions to public API --- CMakeLists.txt | 1 - include/sdbus-c++/ConvenienceApiClasses.h | 12 +- include/sdbus-c++/ConvenienceApiClasses.inl | 98 ++++----- src/ConvenienceApiClasses.cpp | 209 -------------------- src/Object.cpp | 2 + src/Proxy.cpp | 4 + 6 files changed, 48 insertions(+), 278 deletions(-) delete mode 100644 src/ConvenienceApiClasses.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ba9c568..b35679e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,6 @@ set(SDBUSCPP_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include/${SDBUSCPP_INCLUDE_ set(SDBUSCPP_CPP_SRCS ${SDBUSCPP_SOURCE_DIR}/Connection.cpp - ${SDBUSCPP_SOURCE_DIR}/ConvenienceApiClasses.cpp ${SDBUSCPP_SOURCE_DIR}/Error.cpp ${SDBUSCPP_SOURCE_DIR}/Message.cpp ${SDBUSCPP_SOURCE_DIR}/Object.cpp diff --git a/include/sdbus-c++/ConvenienceApiClasses.h b/include/sdbus-c++/ConvenienceApiClasses.h index 1904937..bc530f0 100644 --- a/include/sdbus-c++/ConvenienceApiClasses.h +++ b/include/sdbus-c++/ConvenienceApiClasses.h @@ -53,7 +53,7 @@ namespace sdbus { MethodRegistrator& operator=(MethodRegistrator&& other) = default; ~MethodRegistrator() noexcept(false); - MethodRegistrator& onInterface(const std::string& interfaceName); + MethodRegistrator& onInterface(std::string interfaceName); template std::enable_if_t, MethodRegistrator&> implementedAs(_Function&& callback); template @@ -102,7 +102,7 @@ namespace sdbus { PropertyRegistrator& operator=(PropertyRegistrator&& other) = default; ~PropertyRegistrator() noexcept(false); - PropertyRegistrator& onInterface(const std::string& interfaceName); + PropertyRegistrator& onInterface(std::string interfaceName); template PropertyRegistrator& withGetter(_Function&& callback); template PropertyRegistrator& withSetter(_Function&& callback); PropertyRegistrator& markAsDeprecated(); @@ -205,12 +205,12 @@ namespace sdbus { { public: SignalSubscriber(IProxy& proxy, const std::string& signalName); - SignalSubscriber& onInterface(const std::string& interfaceName); + SignalSubscriber& onInterface(std::string interfaceName); template void call(_Function&& callback); private: IProxy& proxy_; - std::string signalName_; + const std::string& signalName_; std::string interfaceName_; }; @@ -222,14 +222,14 @@ namespace sdbus { private: IProxy& proxy_; - std::string propertyName_; + const std::string& propertyName_; }; class PropertySetter { public: PropertySetter(IProxy& proxy, const std::string& propertyName); - PropertySetter& onInterface(const std::string& interfaceName); + PropertySetter& onInterface(std::string interfaceName); template void toValue(const _Value& value); void toValue(const sdbus::Variant& value); diff --git a/include/sdbus-c++/ConvenienceApiClasses.inl b/include/sdbus-c++/ConvenienceApiClasses.inl index 009edab..a41cd22 100644 --- a/include/sdbus-c++/ConvenienceApiClasses.inl +++ b/include/sdbus-c++/ConvenienceApiClasses.inl @@ -36,7 +36,8 @@ #include #include #include -/*#include */ +#include +#include namespace sdbus { @@ -44,12 +45,10 @@ namespace sdbus { /*** MethodRegistrator ***/ /*** ----------------- ***/ - // Moved into the library to isolate from C++17 dependency - /* inline MethodRegistrator::MethodRegistrator(IObject& object, const std::string& methodName) : object_(object) , methodName_(methodName) - , exceptions_(std::uncaught_exceptions()) // Needs C++17 + , exceptions_(std::uncaught_exceptions()) { } @@ -59,8 +58,8 @@ namespace sdbus { if (std::uncaught_exceptions() != exceptions_) return; - SDBUS_THROW_ERROR_IF(interfaceName_.empty(), "DBus interface not specified when registering a DBus method", EINVAL); - SDBUS_THROW_ERROR_IF(!methodCallback_, "Method handler not specified when registering a DBus method", EINVAL); + assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function + assert(methodCallback_); // implementedAs() must be placed/called prior to this function // registerMethod() can throw. But as the MethodRegistrator shall always be used as an unnamed, // temporary object, i.e. not as a stack-allocated object, the double-exception situation @@ -73,11 +72,10 @@ namespace sdbus { // to the exception thrown from here if the caller is a destructor itself. object_.registerMethod(interfaceName_, methodName_, inputSignature_, outputSignature_, std::move(methodCallback_), flags_); } - */ - inline MethodRegistrator& MethodRegistrator::onInterface(const std::string& interfaceName) + inline MethodRegistrator& MethodRegistrator::onInterface(std::string interfaceName) { - interfaceName_ = interfaceName; + interfaceName_ = std::move(interfaceName); return *this; } @@ -157,11 +155,9 @@ namespace sdbus { /*** SignalRegistrator ***/ /*** ----------------- ***/ - // Moved into the library to isolate from C++17 dependency - /* - inline SignalRegistrator::SignalRegistrator(IObject& object, std::string signalName) + inline SignalRegistrator::SignalRegistrator(IObject& object, const std::string& signalName) : object_(object) - , signalName_(std::move(signalName)) + , signalName_(signalName) , exceptions_(std::uncaught_exceptions()) { } @@ -172,8 +168,7 @@ namespace sdbus { if (std::uncaught_exceptions() != exceptions_) return; - if (interfaceName_.empty()) - throw sdbus::Exception("DBus interface not specified when registering a DBus signal"); + assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function // registerSignal() can throw. But as the SignalRegistrator shall always be used as an unnamed, // temporary object, i.e. not as a stack-allocated object, the double-exception situation @@ -184,9 +179,8 @@ namespace sdbus { // Therefore, we can allow registerSignal() to throw even if we are in the destructor. // Bottomline is, to be on the safe side, the caller must take care of catching and reacting // to the exception thrown from here if the caller is a destructor itself. - object_.registerSignal(interfaceName_, signalName_, signalSignature_); + object_.registerSignal(interfaceName_, signalName_, signalSignature_, flags_); } - */ inline SignalRegistrator& SignalRegistrator::onInterface(std::string interfaceName) { @@ -214,11 +208,9 @@ namespace sdbus { /*** PropertyRegistrator ***/ /*** ------------------- ***/ - // Moved into the library to isolate from C++17 dependency - /* - inline PropertyRegistrator::PropertyRegistrator(IObject& object, std::string propertyName) + inline PropertyRegistrator::PropertyRegistrator(IObject& object, const std::string& propertyName) : object_(object) - , propertyName_(std::move(propertyName)) + , propertyName_(propertyName) , exceptions_(std::uncaught_exceptions()) { } @@ -229,7 +221,7 @@ namespace sdbus { if (std::uncaught_exceptions() != exceptions_) return; - SDBUS_THROW_ERROR_IF(interfaceName_.empty(), "DBus interface not specified when registering a DBus property", EINVAL); + assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function // registerProperty() can throw. But as the PropertyRegistrator shall always be used as an unnamed, // temporary object, i.e. not as a stack-allocated object, the double-exception situation @@ -240,17 +232,17 @@ namespace sdbus { // Therefore, we can allow registerProperty() to throw even if we are in the destructor. // Bottomline is, to be on the safe side, the caller must take care of catching and reacting // to the exception thrown from here if the caller is a destructor itself. - object_.registerProperty( std::move(interfaceName_) - , std::move(propertyName_) - , std::move(propertySignature_) + object_.registerProperty( interfaceName_ + , propertyName_ + , propertySignature_ , std::move(getter_) - , std::move(setter_) ); + , std::move(setter_) + , flags_ ); } - */ - inline PropertyRegistrator& PropertyRegistrator::onInterface(const std::string& interfaceName) + inline PropertyRegistrator& PropertyRegistrator::onInterface(std::string interfaceName) { - interfaceName_ = interfaceName; + interfaceName_ = std::move(interfaceName); return *this; } @@ -323,8 +315,6 @@ namespace sdbus { /*** InterfaceFlagsSetter ***/ /*** -------------------- ***/ - // Moved into the library to isolate from C++17 dependency - /* inline InterfaceFlagsSetter::InterfaceFlagsSetter(IObject& object, const std::string& interfaceName) : object_(object) , interfaceName_(interfaceName) @@ -338,8 +328,6 @@ namespace sdbus { if (std::uncaught_exceptions() != exceptions_) return; - SDBUS_THROW_ERROR_IF(interfaceName_.empty(), "DBus interface not specified when setting its flags", EINVAL); - // setInterfaceFlags() can throw. But as the InterfaceFlagsSetter shall always be used as an unnamed, // temporary object, i.e. not as a stack-allocated object, the double-exception situation // shall never happen. I.e. it should not happen that this destructor is directly called @@ -349,10 +337,8 @@ namespace sdbus { // Therefore, we can allow setInterfaceFlags() to throw even if we are in the destructor. // Bottomline is, to be on the safe side, the caller must take care of catching and reacting // to the exception thrown from here if the caller is a destructor itself. - object_.setInterfaceFlags( std::move(interfaceName_) - , std::move(flags_) ); + object_.setInterfaceFlags(interfaceName_, std::move(flags_)); } - */ inline InterfaceFlagsSetter& InterfaceFlagsSetter::markAsDeprecated() { @@ -386,8 +372,6 @@ namespace sdbus { /*** SignalEmitter ***/ /*** ------------- ***/ - // Moved into the library to isolate from C++17 dependency - /* inline SignalEmitter::SignalEmitter(IObject& object, const std::string& signalName) : object_(object) , signalName_(signalName) @@ -401,9 +385,6 @@ namespace sdbus { if (std::uncaught_exceptions() != exceptions_) return; - if (!signal_.isValid()) - throw sdbus::Exception("DBus interface not specified when emitting a DBus signal"); - // emitSignal() can throw. But as the SignalEmitter shall always be used as an unnamed, // temporary object, i.e. not as a stack-allocated object, the double-exception situation // shall never happen. I.e. it should not happen that this destructor is directly called @@ -415,7 +396,6 @@ namespace sdbus { // to the exception thrown from here if the caller is a destructor itself. object_.emitSignal(signal_); } - */ inline SignalEmitter& SignalEmitter::onInterface(const std::string& interfaceName) { @@ -427,7 +407,7 @@ namespace sdbus { template inline void SignalEmitter::withArguments(_Args&&... args) { - SDBUS_THROW_ERROR_IF(!signal_.isValid(), "DBus interface not specified when emitting a DBus signal", EINVAL); + assert(signal_.isValid()); // onInterface() must be placed/called prior to withArguments() detail::serialize_pack(signal_, std::forward<_Args>(args)...); } @@ -436,9 +416,7 @@ namespace sdbus { /*** MethodInvoker ***/ /*** ------------- ***/ - // Moved into the library to isolate from C++17 dependency - /* - inline MethodInvoker::MethodInvoker(IProxy& proxyObject, const std::string& methodName) + inline MethodInvoker::MethodInvoker(IProxy& proxy, const std::string& methodName) : proxy_(proxy) , methodName_(methodName) , exceptions_(std::uncaught_exceptions()) @@ -452,9 +430,6 @@ namespace sdbus { if (methodCalled_ || std::uncaught_exceptions() != exceptions_) return; - if (!method_.isValid()) - throw sdbus::Exception("DBus interface not specified when calling a DBus method"); - // callMethod() can throw. But as the MethodInvoker shall always be used as an unnamed, // temporary object, i.e. not as a stack-allocated object, the double-exception situation // shall never happen. I.e. it should not happen that this destructor is directly called @@ -464,9 +439,8 @@ namespace sdbus { // Therefore, we can allow callMethod() to throw even if we are in the destructor. // Bottomline is, to be on the safe side, the caller must take care of catching and reacting // to the exception thrown from here if the caller is a destructor itself. - proxy_.callMethod(method_); + proxy_.callMethod(method_, timeout_); } - */ inline MethodInvoker& MethodInvoker::onInterface(const std::string& interfaceName) { @@ -492,7 +466,7 @@ namespace sdbus { template inline MethodInvoker& MethodInvoker::withArguments(_Args&&... args) { - SDBUS_THROW_ERROR_IF(!method_.isValid(), "DBus interface not specified when calling a DBus method", EINVAL); + assert(method_.isValid()); // onInterface() must be placed/called prior to this function detail::serialize_pack(method_, std::forward<_Args>(args)...); @@ -502,7 +476,7 @@ namespace sdbus { template inline void MethodInvoker::storeResultsTo(_Args&... args) { - SDBUS_THROW_ERROR_IF(!method_.isValid(), "DBus interface not specified when calling a DBus method", EINVAL); + assert(method_.isValid()); // onInterface() must be placed/called prior to this function auto reply = proxy_.callMethod(method_, timeout_); methodCalled_ = true; @@ -512,7 +486,7 @@ namespace sdbus { inline void MethodInvoker::dontExpectReply() { - SDBUS_THROW_ERROR_IF(!method_.isValid(), "DBus interface not specified when calling a DBus method", EINVAL); + assert(method_.isValid()); // onInterface() must be placed/called prior to this function method_.dontExpectReply(); } @@ -551,7 +525,7 @@ namespace sdbus { template inline AsyncMethodInvoker& AsyncMethodInvoker::withArguments(_Args&&... args) { - SDBUS_THROW_ERROR_IF(!method_.isValid(), "DBus interface not specified when calling a DBus method", EINVAL); + assert(method_.isValid()); // onInterface() must be placed/called prior to this function detail::serialize_pack(method_, std::forward<_Args>(args)...); @@ -561,7 +535,7 @@ namespace sdbus { template void AsyncMethodInvoker::uponReplyInvoke(_Function&& callback) { - SDBUS_THROW_ERROR_IF(!method_.isValid(), "DBus interface not specified when calling a DBus method", EINVAL); + assert(method_.isValid()); // onInterface() must be placed/called prior to this function auto asyncReplyHandler = [callback = std::forward<_Function>(callback)](MethodReply& reply, const Error* error) { @@ -590,9 +564,9 @@ namespace sdbus { { } - inline SignalSubscriber& SignalSubscriber::onInterface(const std::string& interfaceName) + inline SignalSubscriber& SignalSubscriber::onInterface(std::string interfaceName) { - interfaceName_ = interfaceName; + interfaceName_ = std::move(interfaceName); return *this; } @@ -600,7 +574,7 @@ namespace sdbus { template inline void SignalSubscriber::call(_Function&& callback) { - SDBUS_THROW_ERROR_IF(interfaceName_.empty(), "DBus interface not specified when subscribing to a signal", EINVAL); + assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function proxy_.registerSignalHandler( interfaceName_ , signalName_ @@ -649,9 +623,9 @@ namespace sdbus { { } - inline PropertySetter& PropertySetter::onInterface(const std::string& interfaceName) + inline PropertySetter& PropertySetter::onInterface(std::string interfaceName) { - interfaceName_ = interfaceName; + interfaceName_ = std::move(interfaceName); return *this; } @@ -664,7 +638,7 @@ namespace sdbus { inline void PropertySetter::toValue(const sdbus::Variant& value) { - SDBUS_THROW_ERROR_IF(interfaceName_.empty(), "DBus interface not specified when setting a property", EINVAL); + assert(!interfaceName_.empty()); // onInterface() must be placed/called prior to this function proxy_ .callMethod("Set") diff --git a/src/ConvenienceApiClasses.cpp b/src/ConvenienceApiClasses.cpp deleted file mode 100644 index b900003..0000000 --- a/src/ConvenienceApiClasses.cpp +++ /dev/null @@ -1,209 +0,0 @@ -/** - * (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland - * (C) 2016 - 2019 Stanislav Angelovic - * - * @file ConvenienceApiClasses.cpp - * - * Created on: Jan 19, 2017 - * Project: sdbus-c++ - * Description: High-level D-Bus IPC C++ library based on sd-bus - * - * This file is part of sdbus-c++. - * - * sdbus-c++ is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 2.1 of the License, or - * (at your option) any later version. - * - * sdbus-c++ is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with sdbus-c++. If not, see . - */ - -#include "sdbus-c++/ConvenienceApiClasses.h" -#include "sdbus-c++/IObject.h" -#include "sdbus-c++/IProxy.h" -#include -#include - -namespace sdbus { - -MethodRegistrator::MethodRegistrator(IObject& object, const std::string& methodName) - : object_(object) - , methodName_(methodName) - , exceptions_(std::uncaught_exceptions()) // Needs C++17 -{ -} - -MethodRegistrator::~MethodRegistrator() noexcept(false) // since C++11, destructors must -{ // explicitly be allowed to throw - // Don't register the method if MethodRegistrator threw an exception in one of its methods - if (std::uncaught_exceptions() != exceptions_) - return; - - SDBUS_THROW_ERROR_IF(interfaceName_.empty(), "DBus interface not specified when registering a DBus method", EINVAL); - SDBUS_THROW_ERROR_IF(!methodCallback_, "Method handler not specified when registering a DBus method", EINVAL); - - // registerMethod() can throw. But as the MethodRegistrator shall always be used as an unnamed, - // temporary object, i.e. not as a stack-allocated object, the double-exception situation - // shall never happen. I.e. it should not happen that this destructor is directly called - // in the stack-unwinding process of another flying exception (which would lead to immediate - // termination). It can be called indirectly in the destructor of another object, but that's - // fine and safe provided that the caller catches exceptions thrown from here. - // Therefore, we can allow registerMethod() to throw even if we are in the destructor. - // Bottomline is, to be on the safe side, the caller must take care of catching and reacting - // to the exception thrown from here if the caller is a destructor itself. - object_.registerMethod(interfaceName_, methodName_, inputSignature_, outputSignature_, std::move(methodCallback_), flags_); -} - -SignalRegistrator::SignalRegistrator(IObject& object, const std::string& signalName) - : object_(object) - , signalName_(signalName) - , exceptions_(std::uncaught_exceptions()) // Needs C++17 -{ -} - -SignalRegistrator::~SignalRegistrator() noexcept(false) // since C++11, destructors must -{ // explicitly be allowed to throw - // Don't register the signal if SignalRegistrator threw an exception in one of its methods - if (std::uncaught_exceptions() != exceptions_) - return; - - SDBUS_THROW_ERROR_IF(interfaceName_.empty(), "DBus interface not specified when registering a DBus signal", EINVAL); - - // registerSignal() can throw. But as the SignalRegistrator shall always be used as an unnamed, - // temporary object, i.e. not as a stack-allocated object, the double-exception situation - // shall never happen. I.e. it should not happen that this destructor is directly called - // in the stack-unwinding process of another flying exception (which would lead to immediate - // termination). It can be called indirectly in the destructor of another object, but that's - // fine and safe provided that the caller catches exceptions thrown from here. - // Therefore, we can allow registerSignal() to throw even if we are in the destructor. - // Bottomline is, to be on the safe side, the caller must take care of catching and reacting - // to the exception thrown from here if the caller is a destructor itself. - object_.registerSignal(interfaceName_, signalName_, signalSignature_, flags_); -} - - -PropertyRegistrator::PropertyRegistrator(IObject& object, const std::string& propertyName) - : object_(object) - , propertyName_(propertyName) - , exceptions_(std::uncaught_exceptions()) -{ -} - -PropertyRegistrator::~PropertyRegistrator() noexcept(false) // since C++11, destructors must -{ // explicitly be allowed to throw - // Don't register the property if PropertyRegistrator threw an exception in one of its methods - if (std::uncaught_exceptions() != exceptions_) - return; - - SDBUS_THROW_ERROR_IF(interfaceName_.empty(), "DBus interface not specified when registering a DBus property", EINVAL); - - // registerProperty() can throw. But as the PropertyRegistrator shall always be used as an unnamed, - // temporary object, i.e. not as a stack-allocated object, the double-exception situation - // shall never happen. I.e. it should not happen that this destructor is directly called - // in the stack-unwinding process of another flying exception (which would lead to immediate - // termination). It can be called indirectly in the destructor of another object, but that's - // fine and safe provided that the caller catches exceptions thrown from here. - // Therefore, we can allow registerProperty() to throw even if we are in the destructor. - // Bottomline is, to be on the safe side, the caller must take care of catching and reacting - // to the exception thrown from here if the caller is a destructor itself. - object_.registerProperty( std::move(interfaceName_) - , std::move(propertyName_) - , std::move(propertySignature_) - , std::move(getter_) - , std::move(setter_) - , flags_ ); -} - - -InterfaceFlagsSetter::InterfaceFlagsSetter(IObject& object, const std::string& interfaceName) - : object_(object) - , interfaceName_(interfaceName) - , exceptions_(std::uncaught_exceptions()) -{ -} - -InterfaceFlagsSetter::~InterfaceFlagsSetter() noexcept(false) // since C++11, destructors must -{ // explicitly be allowed to throw - // Don't set any flags if InterfaceFlagsSetter threw an exception in one of its methods - if (std::uncaught_exceptions() != exceptions_) - return; - - SDBUS_THROW_ERROR_IF(interfaceName_.empty(), "DBus interface not specified when setting its flags", EINVAL); - - // setInterfaceFlags() can throw. But as the InterfaceFlagsSetter shall always be used as an unnamed, - // temporary object, i.e. not as a stack-allocated object, the double-exception situation - // shall never happen. I.e. it should not happen that this destructor is directly called - // in the stack-unwinding process of another flying exception (which would lead to immediate - // termination). It can be called indirectly in the destructor of another object, but that's - // fine and safe provided that the caller catches exceptions thrown from here. - // Therefore, we can allow setInterfaceFlags() to throw even if we are in the destructor. - // Bottomline is, to be on the safe side, the caller must take care of catching and reacting - // to the exception thrown from here if the caller is a destructor itself. - object_.setInterfaceFlags( std::move(interfaceName_) - , std::move(flags_) ); -} - - -SignalEmitter::SignalEmitter(IObject& object, const std::string& signalName) - : object_(object) - , signalName_(signalName) - , exceptions_(std::uncaught_exceptions()) // Needs C++17 -{ -} - -SignalEmitter::~SignalEmitter() noexcept(false) // since C++11, destructors must -{ // explicitly be allowed to throw - // Don't emit the signal if SignalEmitter threw an exception in one of its methods - if (std::uncaught_exceptions() != exceptions_) - return; - - SDBUS_THROW_ERROR_IF(!signal_.isValid(), "DBus interface not specified when emitting a DBus signal", EINVAL); - - // emitSignal() can throw. But as the SignalEmitter shall always be used as an unnamed, - // temporary object, i.e. not as a stack-allocated object, the double-exception situation - // shall never happen. I.e. it should not happen that this destructor is directly called - // in the stack-unwinding process of another flying exception (which would lead to immediate - // termination). It can be called indirectly in the destructor of another object, but that's - // fine and safe provided that the caller catches exceptions thrown from here. - // Therefore, we can allow emitSignal() to throw even if we are in the destructor. - // Bottomline is, to be on the safe side, the caller must take care of catching and reacting - // to the exception thrown from here if the caller is a destructor itself. - object_.emitSignal(signal_); -} - - -MethodInvoker::MethodInvoker(IProxy& proxy, const std::string& methodName) - : proxy_(proxy) - , methodName_(methodName) - , exceptions_(std::uncaught_exceptions()) // Needs C++17 -{ -} - -MethodInvoker::~MethodInvoker() noexcept(false) // since C++11, destructors must -{ // explicitly be allowed to throw - // Don't call the method if it has been called already or if MethodInvoker - // threw an exception in one of its methods - if (methodCalled_ || std::uncaught_exceptions() != exceptions_) - return; - - SDBUS_THROW_ERROR_IF(!method_.isValid(), "DBus interface not specified when calling a DBus method", EINVAL); - - // callMethod() can throw. But as the MethodInvoker shall always be used as an unnamed, - // temporary object, i.e. not as a stack-allocated object, the double-exception situation - // shall never happen. I.e. it should not happen that this destructor is directly called - // in the stack-unwinding process of another flying exception (which would lead to immediate - // termination). It can be called indirectly in the destructor of another object, but that's - // fine and safe provided that the caller catches exceptions thrown from here. - // Therefore, we can allow callMethod() to throw even if we are in the destructor. - // Bottomline is, to be on the safe side, the caller must take care of catching and reacting - // to the exception thrown from here if the caller is a destructor itself. - proxy_.callMethod(method_, timeout_); -} - -} diff --git a/src/Object.cpp b/src/Object.cpp index 6ee16a7..d74e27f 100644 --- a/src/Object.cpp +++ b/src/Object.cpp @@ -134,6 +134,8 @@ sdbus::Signal Object::createSignal(const std::string& interfaceName, const std:: void Object::emitSignal(const sdbus::Signal& message) { + SDBUS_THROW_ERROR_IF(!message.isValid(), "Invalid signal message provided", EINVAL); + message.send(); } diff --git a/src/Proxy.cpp b/src/Proxy.cpp index 1f4fe1f..e396f2f 100644 --- a/src/Proxy.cpp +++ b/src/Proxy.cpp @@ -71,11 +71,15 @@ AsyncMethodCall Proxy::createAsyncMethodCall(const std::string& interfaceName, c MethodReply Proxy::callMethod(const MethodCall& message, uint64_t timeout) { + SDBUS_THROW_ERROR_IF(!message.isValid(), "Invalid method call message provided", EINVAL); + return message.send(timeout); } void Proxy::callMethod(const AsyncMethodCall& message, async_reply_handler asyncReplyCallback, uint64_t timeout) { + SDBUS_THROW_ERROR_IF(!message.isValid(), "Invalid async method call message provided", EINVAL); + auto callback = (void*)&Proxy::sdbus_async_reply_handler; auto callData = std::make_unique(AsyncCalls::CallData{*this, std::move(asyncReplyCallback), {}});