mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 10:44:56 +00:00
Bug 1028588 - Make XPCOM refcounting assert against public destructors (leaving aside _INHERITED macros for now) - r=khuey
This commit is contained in:
parent
b369212fc9
commit
c5347881cc
@ -30,6 +30,78 @@
|
|||||||
#include "mozilla/MacroArgs.h"
|
#include "mozilla/MacroArgs.h"
|
||||||
#include "mozilla/MacroForEach.h"
|
#include "mozilla/MacroForEach.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
template <typename T>
|
||||||
|
struct HasDangerousPublicDestructor
|
||||||
|
{
|
||||||
|
static const bool value = false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
// bug 1028428 shows that at least in FreeBSD 10.0 with Clang 3.4 and libc++ 3.4,
|
||||||
|
// std::is_destructible is buggy in that it returns false when it should return true
|
||||||
|
// on ipc::SharedMemory. On the other hand, all Clang versions currently in use
|
||||||
|
// seem to handle the fallback just fine.
|
||||||
|
# define MOZ_CAN_USE_IS_DESTRUCTIBLE_FALLBACK
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
// GCC 4.7 is has buggy std::is_destructible
|
||||||
|
# if MOZ_USING_LIBSTDCXX && MOZ_GCC_VERSION_AT_LEAST(4, 8, 0)
|
||||||
|
# define MOZ_HAVE_STD_IS_DESTRUCTIBLE
|
||||||
|
// Some GCC versions have an ICE when using destructors in decltype().
|
||||||
|
// Works for me on GCC 4.8.2 on Fedora 20 x86-64.
|
||||||
|
# elif MOZ_GCC_VERSION_AT_LEAST(4, 8, 2)
|
||||||
|
# define MOZ_CAN_USE_IS_DESTRUCTIBLE_FALLBACK
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MOZ_HAVE_STD_IS_DESTRUCTIBLE
|
||||||
|
# include <type_traits>
|
||||||
|
# define MOZ_IS_DESTRUCTIBLE(X) (std::is_destructible<X>::value)
|
||||||
|
#elif defined MOZ_CAN_USE_IS_DESTRUCTIBLE_FALLBACK
|
||||||
|
namespace mozilla {
|
||||||
|
struct IsDestructibleFallbackImpl
|
||||||
|
{
|
||||||
|
template<typename T> static T&& Declval();
|
||||||
|
|
||||||
|
template<typename T, typename = decltype(Declval<T>().~T())>
|
||||||
|
static TrueType Test(int);
|
||||||
|
|
||||||
|
template<typename>
|
||||||
|
static FalseType Test(...);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct Selector
|
||||||
|
{
|
||||||
|
typedef decltype(Test<T>(0)) type;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct IsDestructibleFallback
|
||||||
|
: IsDestructibleFallbackImpl::Selector<T>::type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
}
|
||||||
|
# define MOZ_IS_DESTRUCTIBLE(X) (mozilla::IsDestructibleFallback<X>::value)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MOZ_IS_DESTRUCTIBLE
|
||||||
|
#define MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(X) \
|
||||||
|
static_assert(!MOZ_IS_DESTRUCTIBLE(X) || \
|
||||||
|
mozilla::HasDangerousPublicDestructor<X>::value, \
|
||||||
|
"Reference-counted class " #X " should not have a public destructor. " \
|
||||||
|
"Try to make this class's destructor non-public. If that is really " \
|
||||||
|
"not possible, you can whitelist this class by providing a " \
|
||||||
|
"HasDangerousPublicDestructor specialization for it."); \
|
||||||
|
static_assert(!mozilla::HasDangerousPublicDestructor<X>::value || \
|
||||||
|
MOZ_IS_DESTRUCTIBLE(X), \
|
||||||
|
"Class " #X " has no public destructor. That's good! So please " \
|
||||||
|
"remove the HasDangerousPublicDestructor specialization for it.");
|
||||||
|
#else
|
||||||
|
#define MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(X)
|
||||||
|
#endif
|
||||||
|
|
||||||
inline nsISupports*
|
inline nsISupports*
|
||||||
ToSupports(nsISupports* aSupports)
|
ToSupports(nsISupports* aSupports)
|
||||||
{
|
{
|
||||||
@ -334,6 +406,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define NS_IMPL_CC_NATIVE_ADDREF_BODY(_class) \
|
#define NS_IMPL_CC_NATIVE_ADDREF_BODY(_class) \
|
||||||
|
MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
|
||||||
MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
|
MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
|
||||||
NS_ASSERT_OWNINGTHREAD(_class); \
|
NS_ASSERT_OWNINGTHREAD(_class); \
|
||||||
nsrefcnt count = \
|
nsrefcnt count = \
|
||||||
@ -411,78 +484,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
#define NS_INIT_ISUPPORTS() ((void)0)
|
#define NS_INIT_ISUPPORTS() ((void)0)
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
template<typename T>
|
|
||||||
struct HasDangerousPublicDestructor
|
|
||||||
{
|
|
||||||
static const bool value = false;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(__clang__)
|
|
||||||
// bug 1028428 shows that at least in FreeBSD 10.0 with Clang 3.4 and libc++ 3.4,
|
|
||||||
// std::is_destructible is buggy in that it returns false when it should return true
|
|
||||||
// on ipc::SharedMemory. On the other hand, all Clang versions currently in use
|
|
||||||
// seem to handle the fallback just fine.
|
|
||||||
# define MOZ_CAN_USE_IS_DESTRUCTIBLE_FALLBACK
|
|
||||||
#elif defined(__GNUC__)
|
|
||||||
// GCC 4.7 is has buggy std::is_destructible
|
|
||||||
# if MOZ_USING_LIBSTDCXX && MOZ_GCC_VERSION_AT_LEAST(4, 8, 0)
|
|
||||||
# define MOZ_HAVE_STD_IS_DESTRUCTIBLE
|
|
||||||
// Some GCC versions have an ICE when using destructors in decltype().
|
|
||||||
// Works for me on GCC 4.8.2 on Fedora 20 x86-64.
|
|
||||||
# elif MOZ_GCC_VERSION_AT_LEAST(4, 8, 2)
|
|
||||||
# define MOZ_CAN_USE_IS_DESTRUCTIBLE_FALLBACK
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef MOZ_HAVE_STD_IS_DESTRUCTIBLE
|
|
||||||
# include <type_traits>
|
|
||||||
# define MOZ_IS_DESTRUCTIBLE(X) (std::is_destructible<X>::value)
|
|
||||||
#elif defined MOZ_CAN_USE_IS_DESTRUCTIBLE_FALLBACK
|
|
||||||
namespace mozilla {
|
|
||||||
struct IsDestructibleFallbackImpl
|
|
||||||
{
|
|
||||||
template<typename T> static T&& Declval();
|
|
||||||
|
|
||||||
template<typename T, typename = decltype(Declval<T>().~T())>
|
|
||||||
static TrueType Test(int);
|
|
||||||
|
|
||||||
template<typename>
|
|
||||||
static FalseType Test(...);
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct Selector
|
|
||||||
{
|
|
||||||
typedef decltype(Test<T>(0)) type;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct IsDestructibleFallback
|
|
||||||
: IsDestructibleFallbackImpl::Selector<T>::type
|
|
||||||
{
|
|
||||||
};
|
|
||||||
}
|
|
||||||
# define MOZ_IS_DESTRUCTIBLE(X) (mozilla::IsDestructibleFallback<X>::value)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef MOZ_IS_DESTRUCTIBLE
|
|
||||||
#define MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(X) \
|
|
||||||
static_assert(!MOZ_IS_DESTRUCTIBLE(X) || \
|
|
||||||
mozilla::HasDangerousPublicDestructor<X>::value, \
|
|
||||||
"Reference-counted classes should not have a public destructor. " \
|
|
||||||
"Try to make this class's destructor non-public. If that is really " \
|
|
||||||
"not possible, you can whitelist this class by providing a " \
|
|
||||||
"HasDangerousPublicDestructor specialization for it."); \
|
|
||||||
static_assert(!mozilla::HasDangerousPublicDestructor<X>::value || \
|
|
||||||
MOZ_IS_DESTRUCTIBLE(X), \
|
|
||||||
"This class has no public destructor. That's good! So please " \
|
|
||||||
"remove the HasDangerousPublicDestructor specialization for it.");
|
|
||||||
#else
|
|
||||||
#define MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(X)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use this macro to declare and implement the AddRef & Release methods for a
|
* Use this macro to declare and implement the AddRef & Release methods for a
|
||||||
* given non-XPCOM <i>_class</i>.
|
* given non-XPCOM <i>_class</i>.
|
||||||
@ -555,6 +556,7 @@ public:
|
|||||||
#define NS_IMPL_ADDREF(_class) \
|
#define NS_IMPL_ADDREF(_class) \
|
||||||
NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) \
|
NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) \
|
||||||
{ \
|
{ \
|
||||||
|
MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
|
||||||
MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
|
MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
|
||||||
if (!mRefCnt.isThreadSafe) \
|
if (!mRefCnt.isThreadSafe) \
|
||||||
NS_ASSERT_OWNINGTHREAD(_class); \
|
NS_ASSERT_OWNINGTHREAD(_class); \
|
||||||
@ -573,6 +575,7 @@ NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) \
|
|||||||
#define NS_IMPL_ADDREF_USING_AGGREGATOR(_class, _aggregator) \
|
#define NS_IMPL_ADDREF_USING_AGGREGATOR(_class, _aggregator) \
|
||||||
NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) \
|
NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) \
|
||||||
{ \
|
{ \
|
||||||
|
MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
|
||||||
NS_PRECONDITION(_aggregator, "null aggregator"); \
|
NS_PRECONDITION(_aggregator, "null aggregator"); \
|
||||||
return (_aggregator)->AddRef(); \
|
return (_aggregator)->AddRef(); \
|
||||||
}
|
}
|
||||||
@ -648,6 +651,7 @@ NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) \
|
|||||||
#define NS_IMPL_CYCLE_COLLECTING_ADDREF(_class) \
|
#define NS_IMPL_CYCLE_COLLECTING_ADDREF(_class) \
|
||||||
NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) \
|
NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) \
|
||||||
{ \
|
{ \
|
||||||
|
MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
|
||||||
MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
|
MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
|
||||||
NS_ASSERT_OWNINGTHREAD(_class); \
|
NS_ASSERT_OWNINGTHREAD(_class); \
|
||||||
nsISupports *base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \
|
nsISupports *base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \
|
||||||
|
Loading…
Reference in New Issue
Block a user