Skip to content

Commit 3d7955b

Browse files
committed
Bug 1338609: Add the ability to serialize and deserialize structs using Microsoft RPC to mscom; r=jimm
MozReview-Commit-ID: CSkNYCIQYQe --HG-- extra : rebase_source : 8e357eb60adf2040d30f826b1805c35163456aa0
1 parent e648e0f commit 3d7955b

File tree

3 files changed

+297
-0
lines changed

3 files changed

+297
-0
lines changed

ipc/mscom/StructStream.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2+
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3+
/* This Source Code Form is subject to the terms of the Mozilla Public
4+
* License, v. 2.0. If a copy of the MPL was not distributed with this
5+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6+
7+
#include <malloc.h>
8+
#include <rpc.h>
9+
10+
/**
11+
* These functions need to be defined in order for the types that use
12+
* mozilla::mscom::StructToStream and mozilla::mscom::StructFromStream to work.
13+
*/
14+
extern "C" {
15+
16+
void __RPC_FAR* __RPC_USER
17+
midl_user_allocate(size_t aNumBytes)
18+
{
19+
const unsigned long kRpcReqdBufAlignment = 8;
20+
return _aligned_malloc(aNumBytes, kRpcReqdBufAlignment);
21+
}
22+
23+
void __RPC_USER
24+
midl_user_free(void* aBuffer)
25+
{
26+
_aligned_free(aBuffer);
27+
}
28+
29+
} // extern "C"

ipc/mscom/StructStream.h

Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2+
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3+
/* This Source Code Form is subject to the terms of the Mozilla Public
4+
* License, v. 2.0. If a copy of the MPL was not distributed with this
5+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6+
7+
#ifndef mozilla_mscom_StructStream_h
8+
#define mozilla_mscom_StructStream_h
9+
10+
#include "mozilla/Attributes.h"
11+
#include "mozilla/UniquePtr.h"
12+
#include "nscore.h"
13+
14+
#include <memory.h>
15+
#include <midles.h>
16+
#include <objidl.h>
17+
#include <rpc.h>
18+
19+
/**
20+
* This code is used for (de)serializing data structures that have been
21+
* declared using midl, thus allowing us to use Microsoft RPC for marshaling
22+
* data for our COM handlers that may run in other processes that are not ours.
23+
*/
24+
25+
namespace mozilla {
26+
namespace mscom {
27+
28+
namespace detail {
29+
30+
typedef ULONG EncodedLenT;
31+
32+
} // namespace detail
33+
34+
class MOZ_NON_TEMPORARY_CLASS StructToStream
35+
{
36+
public:
37+
/**
38+
* This constructor variant represents an empty/null struct to be serialized.
39+
*/
40+
StructToStream()
41+
: mStatus(RPC_S_OK)
42+
, mHandle(nullptr)
43+
, mBuffer(nullptr)
44+
, mEncodedLen(0)
45+
{
46+
}
47+
48+
template <typename StructT>
49+
StructToStream(StructT& aSrcStruct, void (*aEncodeFnPtr)(handle_t, StructT*))
50+
: mStatus(RPC_X_INVALID_BUFFER)
51+
, mHandle(nullptr)
52+
, mBuffer(nullptr)
53+
, mEncodedLen(0)
54+
{
55+
mStatus = ::MesEncodeDynBufferHandleCreate(&mBuffer, &mEncodedLen,
56+
&mHandle);
57+
if (mStatus != RPC_S_OK) {
58+
return;
59+
}
60+
61+
MOZ_SEH_TRY {
62+
aEncodeFnPtr(mHandle, &aSrcStruct);
63+
} MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
64+
mStatus = ::RpcExceptionCode();
65+
return;
66+
}
67+
68+
if (!mBuffer || !mEncodedLen) {
69+
mStatus = RPC_X_NO_MEMORY;
70+
return;
71+
}
72+
}
73+
74+
~StructToStream()
75+
{
76+
if (mHandle) {
77+
::MesHandleFree(mHandle);
78+
}
79+
}
80+
81+
static unsigned long GetEmptySize()
82+
{
83+
return sizeof(detail::EncodedLenT);
84+
}
85+
86+
static HRESULT WriteEmpty(IStream* aDestStream)
87+
{
88+
StructToStream emptyStruct;
89+
return emptyStruct.Write(aDestStream);
90+
}
91+
92+
explicit operator bool() const
93+
{
94+
return mStatus == RPC_S_OK;
95+
}
96+
97+
bool IsEmpty() const
98+
{
99+
return mStatus == RPC_S_OK && !mEncodedLen;
100+
}
101+
102+
unsigned long GetSize() const
103+
{
104+
return sizeof(mEncodedLen) + mEncodedLen;
105+
}
106+
107+
HRESULT Write(IStream* aDestStream)
108+
{
109+
if (!aDestStream) {
110+
return E_INVALIDARG;
111+
}
112+
if (mStatus != RPC_S_OK) {
113+
return E_FAIL;
114+
}
115+
116+
ULONG bytesWritten;
117+
HRESULT hr = aDestStream->Write(&mEncodedLen, sizeof(mEncodedLen),
118+
&bytesWritten);
119+
if (FAILED(hr)) {
120+
return hr;
121+
}
122+
if (bytesWritten != sizeof(mEncodedLen)) {
123+
return E_UNEXPECTED;
124+
}
125+
126+
if (mBuffer && mEncodedLen) {
127+
hr = aDestStream->Write(mBuffer, mEncodedLen, &bytesWritten);
128+
if (FAILED(hr)) {
129+
return hr;
130+
}
131+
if (bytesWritten != mEncodedLen) {
132+
return E_UNEXPECTED;
133+
}
134+
}
135+
136+
return hr;
137+
}
138+
139+
StructToStream(const StructToStream&) = delete;
140+
StructToStream(StructToStream&&) = delete;
141+
StructToStream& operator=(const StructToStream&) = delete;
142+
StructToStream& operator=(StructToStream&&) = delete;
143+
144+
private:
145+
RPC_STATUS mStatus;
146+
handle_t mHandle;
147+
char* mBuffer;
148+
detail::EncodedLenT mEncodedLen;
149+
};
150+
151+
class MOZ_NON_TEMPORARY_CLASS StructFromStream
152+
{
153+
struct AlignedFreeDeleter
154+
{
155+
void operator()(void* aPtr)
156+
{
157+
::_aligned_free(aPtr);
158+
}
159+
};
160+
161+
static const detail::EncodedLenT kRpcReqdBufAlignment = 8;
162+
163+
public:
164+
explicit StructFromStream(IStream* aStream)
165+
: mStatus(RPC_X_INVALID_BUFFER)
166+
, mHandle(nullptr)
167+
{
168+
MOZ_ASSERT(aStream);
169+
170+
// Read the length of the encoded data first
171+
detail::EncodedLenT encodedLen = 0;
172+
ULONG bytesRead = 0;
173+
HRESULT hr = aStream->Read(&encodedLen, sizeof(encodedLen), &bytesRead);
174+
if (FAILED(hr)) {
175+
return;
176+
}
177+
178+
// NB: Some implementations of IStream return S_FALSE to indicate EOF,
179+
// other implementations return S_OK and set the number of bytes read to 0.
180+
// We must handle both.
181+
if (hr == S_FALSE || !bytesRead) {
182+
mStatus = RPC_S_OBJECT_NOT_FOUND;
183+
return;
184+
}
185+
186+
if (bytesRead != sizeof(encodedLen)) {
187+
return;
188+
}
189+
190+
if (!encodedLen) {
191+
mStatus = RPC_S_OBJECT_NOT_FOUND;
192+
return;
193+
}
194+
195+
MOZ_ASSERT(encodedLen % kRpcReqdBufAlignment == 0);
196+
if (encodedLen % kRpcReqdBufAlignment) {
197+
return;
198+
}
199+
200+
// This memory allocation is fallible
201+
mEncodedBuffer.reset(static_cast<char*>(
202+
::_aligned_malloc(encodedLen, kRpcReqdBufAlignment)));
203+
if (!mEncodedBuffer) {
204+
return;
205+
}
206+
207+
ULONG bytesReadFromStream = 0;
208+
hr = aStream->Read(mEncodedBuffer.get(), encodedLen, &bytesReadFromStream);
209+
if (FAILED(hr) || bytesReadFromStream != encodedLen) {
210+
return;
211+
}
212+
213+
mStatus = ::MesDecodeBufferHandleCreate(mEncodedBuffer.get(), encodedLen,
214+
&mHandle);
215+
}
216+
217+
~StructFromStream()
218+
{
219+
if (mHandle) {
220+
::MesHandleFree(mHandle);
221+
}
222+
}
223+
224+
explicit operator bool() const
225+
{
226+
return mStatus == RPC_S_OK || IsEmpty();
227+
}
228+
229+
bool IsEmpty() const { return mStatus == RPC_S_OBJECT_NOT_FOUND; }
230+
231+
template <typename StructT>
232+
bool Read(StructT* aDestStruct, void (*aDecodeFnPtr)(handle_t, StructT*))
233+
{
234+
if (!aDestStruct || !aDecodeFnPtr || mStatus != RPC_S_OK) {
235+
return false;
236+
}
237+
238+
// NB: Deserialization will fail with BSTRs unless the destination data
239+
// is zeroed out!
240+
ZeroMemory(aDestStruct, sizeof(StructT));
241+
242+
MOZ_SEH_TRY {
243+
aDecodeFnPtr(mHandle, aDestStruct);
244+
} MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
245+
mStatus = ::RpcExceptionCode();
246+
return false;
247+
}
248+
249+
return true;
250+
}
251+
252+
StructFromStream(const StructFromStream&) = delete;
253+
StructFromStream(StructFromStream&&) = delete;
254+
StructFromStream& operator=(const StructFromStream&) = delete;
255+
StructFromStream& operator=(StructFromStream&&) = delete;
256+
257+
private:
258+
RPC_STATUS mStatus;
259+
handle_t mHandle;
260+
UniquePtr<char, AlignedFreeDeleter> mEncodedBuffer;
261+
};
262+
263+
} // namespace mscom
264+
} // namespace mozilla
265+
266+
#endif // mozilla_mscom_StructStream_h

ipc/mscom/moz.build

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ if CONFIG['ACCESSIBILITY']:
3434
'MainThreadHandoff.h',
3535
'MainThreadInvoker.h',
3636
'Registration.h',
37+
'StructStream.h',
3738
'WeakRef.h',
3839
]
3940

@@ -49,6 +50,7 @@ if CONFIG['ACCESSIBILITY']:
4950
'InterceptorLog.cpp',
5051
'MainThreadHandoff.cpp',
5152
'MainThreadInvoker.cpp',
53+
'StructStream.cpp',
5254
]
5355

5456
LOCAL_INCLUDES += [

0 commit comments

Comments
 (0)