Bug 1300476 - Prevent passing references through InvokeAsync - r=froydnj draft
authorGerald Squelart <gsquelart@mozilla.com>
Thu, 27 Oct 2016 15:13:37 +1100
changeset 430453 3062a7441e21617f559accf4476cdafa5575e8ed
parent 430359 9888f1a23001fde6435e1a9ed7e6d3af8dd988d8
child 535216 a1eb740d5046c2017aabbfdbd48deb764abcfe7c
push id33839
push usergsquelart@mozilla.com
push dateThu, 27 Oct 2016 21:19:31 +0000
reviewersfroydnj
bugs1300476, 1313497
milestone52.0a1
Bug 1300476 - Prevent passing references through InvokeAsync - r=froydnj Passing references to an async call is dangerous because referenced objects could be destroyed before/during the call, or even be stored by the callee. The assertion message points at bug 1313497, which is a follow-up to (eventually) re-allow references in a safer manner. MozReview-Commit-ID: FTgI5CGCVAe
xpcom/threads/MozPromise.h
--- a/xpcom/threads/MozPromise.h
+++ b/xpcom/threads/MozPromise.h
@@ -9,16 +9,17 @@
 
 #include "mozilla/AbstractThread.h"
 #include "mozilla/IndexSequence.h"
 #include "mozilla/Logging.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/Monitor.h"
 #include "mozilla/Tuple.h"
+#include "mozilla/TypeTraits.h"
 
 #include "nsTArray.h"
 #include "nsThreadUtils.h"
 
 namespace mozilla {
 
 extern LazyLogModule gMozPromiseLog;
 
@@ -963,23 +964,42 @@ public:
     return NS_OK;
   }
 
 private:
   RefPtr<typename PromiseType::Private> mProxyPromise;
   nsAutoPtr<MethodCall<PromiseType, ThisType, ArgTypes...>> mMethodCall;
 };
 
+constexpr bool Any()
+{
+  return false;
+}
+
+template <typename T1>
+constexpr bool Any(T1 a)
+{
+  return static_cast<bool>(a);
+}
+
+template <typename T1, typename... Ts>
+constexpr bool Any(T1 a, Ts... aOthers)
+{
+  return a || Any(aOthers...);
+}
+
 } // namespace detail
 
 template<typename PromiseType, typename ThisType, typename ...ArgTypes, typename ...ActualArgTypes>
 static RefPtr<PromiseType>
 InvokeAsync(AbstractThread* aTarget, ThisType* aThisVal, const char* aCallerName,
             RefPtr<PromiseType>(ThisType::*aMethod)(ArgTypes...), ActualArgTypes&&... aArgs)
 {
+  static_assert(!detail::Any(IsReference<ArgTypes>::value...),
+                "Cannot pass reference types through InvokeAsync, see bug 1313497 if you require it");
   typedef detail::MethodCall<PromiseType, ThisType, ArgTypes...> MethodCallType;
   typedef detail::ProxyRunnable<PromiseType, ThisType, ArgTypes...> ProxyRunnableType;
 
   MethodCallType* methodCall = new MethodCallType(aMethod, aThisVal, Forward<ActualArgTypes>(aArgs)...);
   RefPtr<typename PromiseType::Private> p = new (typename PromiseType::Private)(aCallerName);
   RefPtr<ProxyRunnableType> r = new ProxyRunnableType(p, methodCall);
   MOZ_ASSERT(aTarget->IsDispatchReliable());
   aTarget->Dispatch(r.forget());