Bug 1315638: Modify MainThreadHandoff::FixArrayElements to be able to distinguish between outparams with different levels of indirection; r?jimm draft
authorAaron Klotz <aklotz@mozilla.com>
Mon, 07 Nov 2016 16:04:06 -0700
changeset 435058 3378995dcf197a53ad00f39569a0f1e7d6ff7781
parent 435057 affce9c1a603906284f74cb92c085e67f123bdf0
child 435493 5cc96edf9bad1cc8a26451dd8af8c5baad12aad7
push id34917
push useraklotz@mozilla.com
push dateMon, 07 Nov 2016 23:04:54 +0000
reviewersjimm
bugs1315638
milestone52.0a1
Bug 1315638: Modify MainThreadHandoff::FixArrayElements to be able to distinguish between outparams with different levels of indirection; r?jimm MozReview-Commit-ID: HZgED9JT16m
accessible/ipc/win/PlatformChild.cpp
ipc/mscom/MainThreadHandoff.cpp
ipc/mscom/Registration.h
--- a/accessible/ipc/win/PlatformChild.cpp
+++ b/accessible/ipc/win/PlatformChild.cpp
@@ -23,20 +23,24 @@ namespace a11y {
  * outparams. Instead we manually define the relevant metadata here, and
  * register it in a call to mozilla::mscom::RegisterArrayData.
  * @see mozilla::mscom::ArrayData
  */
 static const mozilla::mscom::ArrayData sPlatformChildArrayData[] = {
   {IID_IEnumVARIANT, 3, 1, VT_DISPATCH, IID_IDispatch, 2},
   {IID_IAccessible2, 30, 1, VT_UNKNOWN | VT_BYREF, IID_IAccessibleRelation, 2},
   {IID_IAccessibleRelation, 7, 1, VT_UNKNOWN | VT_BYREF, IID_IUnknown, 2},
-  {IID_IAccessible2_2, 48, 2, VT_UNKNOWN | VT_BYREF, IID_IUnknown, 3},
-  {IID_IAccessibleTableCell, 4, 0, VT_UNKNOWN | VT_BYREF, IID_IUnknown, 1},
-  {IID_IAccessibleTableCell, 7, 0, VT_UNKNOWN | VT_BYREF, IID_IUnknown, 1},
-  {IID_IAccessibleHypertext2, 25, 0, VT_UNKNOWN | VT_BYREF, IID_IUnknown, 1}
+  {IID_IAccessible2_2, 48, 2, VT_UNKNOWN | VT_BYREF, IID_IUnknown, 3,
+   mozilla::mscom::ArrayData::Flag::eAllocatedByServer},
+  {IID_IAccessibleTableCell, 4, 0, VT_UNKNOWN | VT_BYREF, IID_IUnknown, 1,
+   mozilla::mscom::ArrayData::Flag::eAllocatedByServer},
+  {IID_IAccessibleTableCell, 7, 0, VT_UNKNOWN | VT_BYREF, IID_IUnknown, 1,
+   mozilla::mscom::ArrayData::Flag::eAllocatedByServer},
+  {IID_IAccessibleHypertext2, 25, 0, VT_UNKNOWN | VT_BYREF, IID_IUnknown, 1,
+   mozilla::mscom::ArrayData::Flag::eAllocatedByServer}
 };
 
 // Type libraries are thread-neutral, so we can register those from any
 // apartment. OTOH, proxies must be registered from within the apartment where
 // we intend to instantiate them. Therefore RegisterProxy() must be called
 // via EnsureMTA.
 PlatformChild::PlatformChild()
   : mAccTypelib(mozilla::mscom::RegisterTypelib(L"oleacc.dll",
--- a/ipc/mscom/MainThreadHandoff.cpp
+++ b/ipc/mscom/MainThreadHandoff.cpp
@@ -253,20 +253,28 @@ MainThreadHandoff::FixArrayElements(ICal
     // ICallFrame::GetParam is not able to coerce the param into a VARIANT.
     // That's ok, we can try to do it ourselves.
     CALLFRAMEPARAMINFO paramInfo;
     hr = aFrame->GetParamInfo(aArrayData.mArrayParamIndex, &paramInfo);
     if (FAILED(hr)) {
       return hr;
     }
     PVOID stackBase = aFrame->GetStackLocation();
-    // We dereference because we need to obtain the value of a parameter
-    // from a stack offset. This pointer is the base of the array.
-    arrayPtr = *reinterpret_cast<PVOID*>(reinterpret_cast<PBYTE>(stackBase) +
-                                         paramInfo.stackOffset);
+    if (aArrayData.mFlag == ArrayData::Flag::eAllocatedByServer) {
+      // In order for the server to allocate the array's buffer and store it in
+      // an outparam, the parameter must be typed as Type***. Since the base
+      // of the array is Type*, we must dereference twice.
+      arrayPtr = **reinterpret_cast<PVOID**>(reinterpret_cast<PBYTE>(stackBase) +
+                                             paramInfo.stackOffset);
+    } else {
+      // We dereference because we need to obtain the value of a parameter
+      // from a stack offset. This pointer is the base of the array.
+      arrayPtr = *reinterpret_cast<PVOID*>(reinterpret_cast<PBYTE>(stackBase) +
+                                           paramInfo.stackOffset);
+    }
   } else if (FAILED(hr)) {
     return hr;
   } else {
     arrayPtr = ResolveArrayPtr(paramVal);
   }
 
   MOZ_ASSERT(arrayPtr);
   if (!arrayPtr) {
--- a/ipc/mscom/Registration.h
+++ b/ipc/mscom/Registration.h
@@ -80,47 +80,59 @@ UniquePtr<RegisteredProxy> RegisterTypel
  * The COM interceptor uses type library information to build its interface
  * proxies. Unfortunately type libraries do not encode size_is and length_is
  * annotations that have been specified in IDL. This structure allows us to
  * explicitly declare such relationships so that the COM interceptor may
  * be made aware of them.
  */
 struct ArrayData
 {
+  enum class Flag
+  {
+    eNone = 0,
+    eAllocatedByServer = 1 // This implies an extra level of indirection
+  };
+
   ArrayData(REFIID aIid, ULONG aMethodIndex, ULONG aArrayParamIndex,
             VARTYPE aArrayParamType, REFIID aArrayParamIid,
-            ULONG aLengthParamIndex)
+            ULONG aLengthParamIndex, Flag aFlag = Flag::eNone)
     : mIid(aIid)
     , mMethodIndex(aMethodIndex)
     , mArrayParamIndex(aArrayParamIndex)
     , mArrayParamType(aArrayParamType)
     , mArrayParamIid(aArrayParamIid)
     , mLengthParamIndex(aLengthParamIndex)
+    , mFlag(aFlag)
   {
   }
+
   ArrayData(const ArrayData& aOther)
   {
     *this = aOther;
   }
+
   ArrayData& operator=(const ArrayData& aOther)
   {
     mIid = aOther.mIid;
     mMethodIndex = aOther.mMethodIndex;
     mArrayParamIndex = aOther.mArrayParamIndex;
     mArrayParamType = aOther.mArrayParamType;
     mArrayParamIid = aOther.mArrayParamIid;
     mLengthParamIndex = aOther.mLengthParamIndex;
+    mFlag = aOther.mFlag;
     return *this;
   }
+
   IID     mIid;
   ULONG   mMethodIndex;
   ULONG   mArrayParamIndex;
   VARTYPE mArrayParamType;
   IID     mArrayParamIid;
   ULONG   mLengthParamIndex;
+  Flag    mFlag;
 };
 
 void RegisterArrayData(const ArrayData* aArrayData, size_t aLength);
 
 template <size_t N>
 inline void
 RegisterArrayData(const ArrayData (&aData)[N])
 {