diff options
-rw-r--r-- | base/callback.h | 5 | ||||
-rw-r--r-- | base/raw_scoped_refptr_mismatch_checker.h | 225 | ||||
-rw-r--r-- | base/task.h | 15 | ||||
-rw-r--r-- | base/template_util.h | 47 |
4 files changed, 151 insertions, 141 deletions
diff --git a/base/callback.h b/base/callback.h index 7f2eb70..e5ea771 100644 --- a/base/callback.h +++ b/base/callback.h @@ -206,8 +206,9 @@ template <class T, class Method, class Params> class UnboundMethod { public: UnboundMethod(Method m, const Params& p) : m_(m), p_(p) { - COMPILE_ASSERT((MethodUsesScopedRefptrCorrectly<Method, Params>::value), - badunboundmethodparams); + COMPILE_ASSERT( + (base::internal::ParamsUseScopedRefptrCorrectly<Params>::value), + badunboundmethodparams); } void Run(T* obj) const { DispatchToMethod(obj, m_, p_); diff --git a/base/raw_scoped_refptr_mismatch_checker.h b/base/raw_scoped_refptr_mismatch_checker.h index d2913e7..b79cfb5 100644 --- a/base/raw_scoped_refptr_mismatch_checker.h +++ b/base/raw_scoped_refptr_mismatch_checker.h @@ -7,165 +7,124 @@ #pragma once #include "base/ref_counted.h" +#include "base/template_util.h" #include "base/tuple.h" +#include "build/build_config.h" -// It is dangerous to post a task with a raw pointer argument to a function -// that expects a scoped_refptr<>. The compiler will happily accept the -// situation, but it will not attempt to increase the refcount until the task -// runs. Callers expecting the argument to be refcounted up at post time are -// in for a nasty surprise! Example: http://crbug.com/27191 +// It is dangerous to post a task with a T* argument where T is a subtype of +// RefCounted(Base|ThreadSafeBase), since by the time the parameter is used, the +// object may already have been deleted since it was not held with a +// scoped_refptr. Example: http://crbug.com/27191 // The following set of traits are designed to generate a compile error // whenever this antipattern is attempted. -template <class A, class B> -struct ExpectsScopedRefptrButGetsRawPtr { + +namespace base { + +// This is a base internal implementation file used by task.h and callback.h. +// Not for public consumption, so we wrap it in namespace internal. +namespace internal { + +template <typename T> +struct NeedsScopedRefptrButGetsRawPtr { +#if defined(OS_WIN) + enum { + value = base::false_type::value + }; +#else + enum { + // Human readable translation: you needed to be a scoped_refptr if you are a + // raw pointer type and are convertible to a RefCounted(Base|ThreadSafeBase) + // type. + value = (is_pointer<T>::value && + (is_convertible<T, subtle::RefCountedBase*>::value || + is_convertible<T, subtle::RefCountedThreadSafeBase*>::value)) + }; +#endif +}; + +template <typename Params> +struct ParamsUseScopedRefptrCorrectly { enum { value = 0 }; }; -template <class A, class B> -struct ExpectsScopedRefptrButGetsRawPtr<scoped_refptr<A>, B*> { +template <> +struct ParamsUseScopedRefptrCorrectly<Tuple0> { enum { value = 1 }; }; -template <class Function, class Params> -struct FunctionUsesScopedRefptrCorrectly { - enum { value = 1 }; +template <typename A> +struct ParamsUseScopedRefptrCorrectly<Tuple1<A> > { + enum { value = !NeedsScopedRefptrButGetsRawPtr<A>::value }; }; -template <class A1, class A2> -struct FunctionUsesScopedRefptrCorrectly<void (*)(A1), Tuple1<A2> > { - enum { value = !ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value }; +template <typename A, typename B> +struct ParamsUseScopedRefptrCorrectly<Tuple2<A, B> > { + enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value || + NeedsScopedRefptrButGetsRawPtr<B>::value) }; }; -template <class A1, class B1, class A2, class B2> -struct FunctionUsesScopedRefptrCorrectly<void (*)(A1, B1), Tuple2<A2, B2> > { - enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value || - ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value) }; +template <typename A, typename B, typename C> +struct ParamsUseScopedRefptrCorrectly<Tuple3<A, B, C> > { + enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value || + NeedsScopedRefptrButGetsRawPtr<B>::value || + NeedsScopedRefptrButGetsRawPtr<C>::value) }; }; -template <class A1, class B1, class C1, class A2, class B2, class C2> -struct FunctionUsesScopedRefptrCorrectly<void (*)(A1, B1, C1), - Tuple3<A2, B2, C2> > { - enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value || - ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value || - ExpectsScopedRefptrButGetsRawPtr<C1, C2>::value) }; +template <typename A, typename B, typename C, typename D> +struct ParamsUseScopedRefptrCorrectly<Tuple4<A, B, C, D> > { + enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value || + NeedsScopedRefptrButGetsRawPtr<B>::value || + NeedsScopedRefptrButGetsRawPtr<C>::value || + NeedsScopedRefptrButGetsRawPtr<D>::value) }; }; -template <class A1, class B1, class C1, class D1, - class A2, class B2, class C2, class D2> -struct FunctionUsesScopedRefptrCorrectly<void (*)(A1, B1, C1, D1), - Tuple4<A2, B2, C2, D2> > { - enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value || - ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value || - ExpectsScopedRefptrButGetsRawPtr<C1, C2>::value || - ExpectsScopedRefptrButGetsRawPtr<D1, D2>::value) }; +template <typename A, typename B, typename C, typename D, typename E> +struct ParamsUseScopedRefptrCorrectly<Tuple5<A, B, C, D, E> > { + enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value || + NeedsScopedRefptrButGetsRawPtr<B>::value || + NeedsScopedRefptrButGetsRawPtr<C>::value || + NeedsScopedRefptrButGetsRawPtr<D>::value || + NeedsScopedRefptrButGetsRawPtr<E>::value) }; }; -template <class A1, class B1, class C1, class D1, class E1, - class A2, class B2, class C2, class D2, class E2> -struct FunctionUsesScopedRefptrCorrectly<void (*)(A1, B1, C1, D1, E1), - Tuple5<A2, B2, C2, D2, E2> > { - enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value || - ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value || - ExpectsScopedRefptrButGetsRawPtr<C1, C2>::value || - ExpectsScopedRefptrButGetsRawPtr<D1, D2>::value || - ExpectsScopedRefptrButGetsRawPtr<E1, E2>::value) }; +template <typename A, typename B, typename C, typename D, typename E, + typename F> +struct ParamsUseScopedRefptrCorrectly<Tuple6<A, B, C, D, E, F> > { + enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value || + NeedsScopedRefptrButGetsRawPtr<B>::value || + NeedsScopedRefptrButGetsRawPtr<C>::value || + NeedsScopedRefptrButGetsRawPtr<D>::value || + NeedsScopedRefptrButGetsRawPtr<E>::value || + NeedsScopedRefptrButGetsRawPtr<F>::value) }; }; -template <class A1, class B1, class C1, class D1, class E1, class F1, - class A2, class B2, class C2, class D2, class E2, class F2> -struct FunctionUsesScopedRefptrCorrectly<void (*)(A1, B1, C1, D1, E1, F1), - Tuple6<A2, B2, C2, D2, E2, F2> > { - enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value || - ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value || - ExpectsScopedRefptrButGetsRawPtr<C1, C2>::value || - ExpectsScopedRefptrButGetsRawPtr<D1, D2>::value || - ExpectsScopedRefptrButGetsRawPtr<E1, E2>::value || - ExpectsScopedRefptrButGetsRawPtr<F1, F2>::value) }; +template <typename A, typename B, typename C, typename D, typename E, + typename F, typename G> +struct ParamsUseScopedRefptrCorrectly<Tuple7<A, B, C, D, E, F, G> > { + enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value || + NeedsScopedRefptrButGetsRawPtr<B>::value || + NeedsScopedRefptrButGetsRawPtr<C>::value || + NeedsScopedRefptrButGetsRawPtr<D>::value || + NeedsScopedRefptrButGetsRawPtr<E>::value || + NeedsScopedRefptrButGetsRawPtr<F>::value || + NeedsScopedRefptrButGetsRawPtr<G>::value) }; }; -template <class A1, class B1, class C1, class D1, class E1, class F1, class G1, - class A2, class B2, class C2, class D2, class E2, class F2, class G2> -struct FunctionUsesScopedRefptrCorrectly<void (*)(A1, B1, C1, D1, E1, F1, G1), - Tuple7<A2, B2, C2, D2, E2, F2, G2> > { - enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value || - ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value || - ExpectsScopedRefptrButGetsRawPtr<C1, C2>::value || - ExpectsScopedRefptrButGetsRawPtr<D1, D2>::value || - ExpectsScopedRefptrButGetsRawPtr<E1, E2>::value || - ExpectsScopedRefptrButGetsRawPtr<F1, F2>::value || - ExpectsScopedRefptrButGetsRawPtr<G1, G2>::value) }; +template <typename A, typename B, typename C, typename D, typename E, + typename F, typename G, typename H> +struct ParamsUseScopedRefptrCorrectly<Tuple8<A, B, C, D, E, F, G, H> > { + enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value || + NeedsScopedRefptrButGetsRawPtr<B>::value || + NeedsScopedRefptrButGetsRawPtr<C>::value || + NeedsScopedRefptrButGetsRawPtr<D>::value || + NeedsScopedRefptrButGetsRawPtr<E>::value || + NeedsScopedRefptrButGetsRawPtr<F>::value || + NeedsScopedRefptrButGetsRawPtr<G>::value || + NeedsScopedRefptrButGetsRawPtr<H>::value) }; }; -template <class Method, class Params> -struct MethodUsesScopedRefptrCorrectly { - enum { value = 1 }; -}; +} // namespace internal -template <class T, class A1, class A2> -struct MethodUsesScopedRefptrCorrectly<void (T::*)(A1), Tuple1<A2> > { - enum { value = !ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value }; -}; - -template <class T, class A1, class B1, class A2, class B2> -struct MethodUsesScopedRefptrCorrectly<void (T::*)(A1, B1), Tuple2<A2, B2> > { - enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value || - ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value) }; -}; - -template <class T, class A1, class B1, class C1, - class A2, class B2, class C2> -struct MethodUsesScopedRefptrCorrectly<void (T::*)(A1, B1, C1), - Tuple3<A2, B2, C2> > { - enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value || - ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value || - ExpectsScopedRefptrButGetsRawPtr<C1, C2>::value) }; -}; - -template <class T, class A1, class B1, class C1, class D1, - class A2, class B2, class C2, class D2> -struct MethodUsesScopedRefptrCorrectly<void (T::*)(A1, B1, C1, D1), - Tuple4<A2, B2, C2, D2> > { - enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value || - ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value || - ExpectsScopedRefptrButGetsRawPtr<C1, C2>::value || - ExpectsScopedRefptrButGetsRawPtr<D1, D2>::value) }; -}; - -template <class T, class A1, class B1, class C1, class D1, class E1, - class A2, class B2, class C2, class D2, class E2> -struct MethodUsesScopedRefptrCorrectly<void (T::*)(A1, B1, C1, D1, E1), - Tuple5<A2, B2, C2, D2, E2> > { - enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value || - ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value || - ExpectsScopedRefptrButGetsRawPtr<C1, C2>::value || - ExpectsScopedRefptrButGetsRawPtr<D1, D2>::value || - ExpectsScopedRefptrButGetsRawPtr<E1, E2>::value) }; -}; - -template <class T, class A1, class B1, class C1, class D1, class E1, class F1, - class A2, class B2, class C2, class D2, class E2, class F2> -struct MethodUsesScopedRefptrCorrectly<void (T::*)(A1, B1, C1, D1, E1, F1), - Tuple6<A2, B2, C2, D2, E2, F2> > { - enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value || - ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value || - ExpectsScopedRefptrButGetsRawPtr<C1, C2>::value || - ExpectsScopedRefptrButGetsRawPtr<D1, D2>::value || - ExpectsScopedRefptrButGetsRawPtr<E1, E2>::value || - ExpectsScopedRefptrButGetsRawPtr<F1, F2>::value) }; -}; - -template <class T, - class A1, class B1, class C1, class D1, class E1, class F1, class G1, - class A2, class B2, class C2, class D2, class E2, class F2, class G2> -struct MethodUsesScopedRefptrCorrectly<void (T::*)(A1, B1, C1, D1, E1, F1, G1), - Tuple7<A2, B2, C2, D2, E2, F2, G2> > { - enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value || - ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value || - ExpectsScopedRefptrButGetsRawPtr<C1, C2>::value || - ExpectsScopedRefptrButGetsRawPtr<D1, D2>::value || - ExpectsScopedRefptrButGetsRawPtr<E1, E2>::value || - ExpectsScopedRefptrButGetsRawPtr<F1, F2>::value || - ExpectsScopedRefptrButGetsRawPtr<G1, G2>::value) }; -}; +} // namespace base #endif // BASE_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_ diff --git a/base/task.h b/base/task.h index b21ccd8..1949e74 100644 --- a/base/task.h +++ b/base/task.h @@ -149,8 +149,9 @@ class ScopedRunnableMethodFactory { : obj_(obj), meth_(meth), params_(params) { - COMPILE_ASSERT((MethodUsesScopedRefptrCorrectly<Method, Params>::value), - badscopedrunnablemethodparams); + COMPILE_ASSERT( + (base::internal::ParamsUseScopedRefptrCorrectly<Params>::value), + badscopedrunnablemethodparams); } virtual void Run() { @@ -317,8 +318,9 @@ class RunnableMethod : public CancelableTask { RunnableMethod(T* obj, Method meth, const Params& params) : obj_(obj), meth_(meth), params_(params) { traits_.RetainCallee(obj_); - COMPILE_ASSERT((MethodUsesScopedRefptrCorrectly<Method, Params>::value), - badrunnablemethodparams); + COMPILE_ASSERT( + (base::internal::ParamsUseScopedRefptrCorrectly<Params>::value), + badrunnablemethodparams); } ~RunnableMethod() { @@ -429,8 +431,9 @@ class RunnableFunction : public CancelableTask { public: RunnableFunction(Function function, const Params& params) : function_(function), params_(params) { - COMPILE_ASSERT((FunctionUsesScopedRefptrCorrectly<Function, Params>::value), - badrunnablefunctionparams); + COMPILE_ASSERT( + (base::internal::ParamsUseScopedRefptrCorrectly<Params>::value), + badrunnablefunctionparams); } ~RunnableFunction() { diff --git a/base/template_util.h b/base/template_util.h index 2cfe04c..27bdb73 100644 --- a/base/template_util.h +++ b/base/template_util.h @@ -6,6 +6,8 @@ #define BASE_TEMPLATE_UTIL_H_ #pragma once +#include "build/build_config.h" + namespace base { // template definitions from tr1 @@ -25,6 +27,51 @@ typedef integral_constant<bool, false> false_type; template <class T> struct is_pointer : false_type {}; template <class T> struct is_pointer<T*> : true_type {}; +namespace internal { + +// Types small_ and big_ are guaranteed such that sizeof(small_) < +// sizeof(big_) +typedef char small_; + +struct big_ { + small_ dummy[2]; +}; + +#if !defined(OS_WIN) + +// This class is an implementation detail for is_convertible, and you +// don't need to know how it works to use is_convertible. For those +// who care: we declare two different functions, one whose argument is +// of type To and one with a variadic argument list. We give them +// return types of different size, so we can use sizeof to trick the +// compiler into telling us which function it would have chosen if we +// had called it with an argument of type From. See Alexandrescu's +// _Modern C++ Design_ for more details on this sort of trick. + +template <typename From, typename To> +struct ConvertHelper { + static small_ Test(To); + static big_ Test(...); + static From Create(); +}; + +#endif // !defined(OS_WIN) + +} // namespace internal + +#if !defined(OS_WIN) + +// Inherits from true_type if From is convertible to To, false_type otherwise. +template <typename From, typename To> +struct is_convertible + : integral_constant<bool, + sizeof(internal::ConvertHelper<From, To>::Test( + internal::ConvertHelper<From, To>::Create())) + == sizeof(internal::small_)> { +}; + +#endif // !defined(OS_WIN) + } // namespace base #endif // BASE_TEMPLATE_UTIL_H_ |