diff options
-rw-r--r-- | base/base.gyp | 1 | ||||
-rw-r--r-- | base/raw_scoped_refptr_mismatch_checker.h | 170 | ||||
-rw-r--r-- | base/task.h | 12 |
3 files changed, 182 insertions, 1 deletions
diff --git a/base/base.gyp b/base/base.gyp index 23b85b1..3373f5a 100644 --- a/base/base.gyp +++ b/base/base.gyp @@ -254,6 +254,7 @@ 'rand_util.h', 'rand_util_posix.cc', 'rand_util_win.cc', + 'raw_scoped_refptr_mismatch_checker.h', 'ref_counted.cc', 'ref_counted.h', 'ref_counted_memory.h', diff --git a/base/raw_scoped_refptr_mismatch_checker.h b/base/raw_scoped_refptr_mismatch_checker.h new file mode 100644 index 0000000..598710f --- /dev/null +++ b/base/raw_scoped_refptr_mismatch_checker.h @@ -0,0 +1,170 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_ +#define BASE_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_ + +#include "base/ref_counted.h" +#include "base/tuple.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 +// The following set of traits are designed to generate a compile error +// whenever this antipattern is attempted. +template <class A, class B> +struct ExpectsScopedRefptrButGetsRawPtr { + enum { value = 0 }; +}; + +template <class A, class B> +struct ExpectsScopedRefptrButGetsRawPtr<scoped_refptr<A>, B*> { + enum { value = 1 }; +}; + +template <class Function, class Params> +struct FunctionUsesScopedRefptrCorrectly { + enum { value = 1 }; +}; + +template <class A1, class A2> +struct FunctionUsesScopedRefptrCorrectly<void (*)(A1), Tuple1<A2> > { + enum { value = !ExpectsScopedRefptrButGetsRawPtr<A1, A2>::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 <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 <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 <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 <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 <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 <class Method, class Params> +struct MethodUsesScopedRefptrCorrectly { + enum { value = 1 }; +}; + +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) }; +}; + +#endif // BASE_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_ diff --git a/base/task.h b/base/task.h index 0fb144b..7c2f393 100644 --- a/base/task.h +++ b/base/task.h @@ -6,6 +6,7 @@ #define BASE_TASK_H_ #include "base/non_thread_safe.h" +#include "base/raw_scoped_refptr_mismatch_checker.h" #include "base/tracked.h" #include "base/tuple.h" #include "base/weak_ptr.h" @@ -140,6 +141,8 @@ class ScopedRunnableMethodFactory { : obj_(obj), meth_(meth), params_(params) { + COMPILE_ASSERT((MethodUsesScopedRefptrCorrectly<Method, Params>::value), + badscopedrunnablemethodparams); } virtual void Run() { @@ -273,6 +276,8 @@ 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); } ~RunnableMethod() { @@ -383,6 +388,8 @@ class RunnableFunction : public CancelableTask { public: RunnableFunction(Function function, const Params& params) : function_(function), params_(params) { + COMPILE_ASSERT((FunctionUsesScopedRefptrCorrectly<Function, Params>::value), + badrunnablefunctionparams); } ~RunnableFunction() { @@ -642,7 +649,10 @@ typename Callback5<Arg1, Arg2, Arg3, Arg4, Arg5>::Type* NewCallback( template <class T, class Method, class Params> class UnboundMethod { public: - UnboundMethod(Method m, Params p) : m_(m), p_(p) {} + UnboundMethod(Method m, Params p) : m_(m), p_(p) { + COMPILE_ASSERT((MethodUsesScopedRefptrCorrectly<Method, Params>::value), + badunboundmethodparams); + } void Run(T* obj) const { DispatchToMethod(obj, m_, p_); } |