[PATCH 1/2] rpcrt4: Add some tests for marshalling interface pointers.

Zebediah Figura z.figura12 at gmail.com
Tue Oct 30 18:28:52 CDT 2018


Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
 dlls/rpcrt4/tests/ndr_marshall.c | 276 +++++++++++++++++++++++++++++++
 1 file changed, 276 insertions(+)

diff --git a/dlls/rpcrt4/tests/ndr_marshall.c b/dlls/rpcrt4/tests/ndr_marshall.c
index de2fd0151a..5da03e2ef7 100644
--- a/dlls/rpcrt4/tests/ndr_marshall.c
+++ b/dlls/rpcrt4/tests/ndr_marshall.c
@@ -21,6 +21,7 @@
 #define _WIN32_WINNT  0x0500
 #define NTDDI_WIN2K   0x05000000
 #define NTDDI_VERSION NTDDI_WIN2K /* for some MIDL_STUB_MESSAGE fields */
+#define COBJMACROS
 
 #include <stdarg.h>
 
@@ -1173,6 +1174,280 @@ static void test_simple_struct(void)
     test_pointer_marshal(fmtstr_pointer_struct, &ps1, 17, wiredata, 21, ps1_cmp, 2, "pointer_struct");
 }
 
+struct testiface
+{
+    IPersist IPersist_iface;
+    LONG ref;
+};
+
+static struct testiface *impl_from_IPersist(IPersist *iface)
+{
+    return CONTAINING_RECORD(iface, struct testiface, IPersist_iface);
+}
+
+static HRESULT WINAPI test_persist_QueryInterface(IPersist *iface, REFIID iid, void **out)
+{
+    if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IPersist))
+    {
+        *out = iface;
+        IPersist_AddRef(iface);
+        return S_OK;
+    }
+
+    *out = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI test_persist_AddRef(IPersist *iface)
+{
+    struct testiface *unk = impl_from_IPersist(iface);
+    return ++unk->ref;
+}
+
+static ULONG WINAPI test_persist_Release(IPersist *iface)
+{
+    struct testiface *unk = impl_from_IPersist(iface);
+    return --unk->ref;
+}
+
+static HRESULT WINAPI test_persist_GetClassId(IPersist *iface, GUID *clsid)
+{
+    *clsid = IID_IPersist;
+    return S_OK;
+}
+
+static IPersistVtbl testiface_vtbl = {
+    test_persist_QueryInterface,
+    test_persist_AddRef,
+    test_persist_Release,
+    test_persist_GetClassId,
+};
+
+static void test_iface_ptr(void)
+{
+    struct testiface server_obj = {{&testiface_vtbl}, 1};
+    struct testiface client_obj = {{&testiface_vtbl}, 1};
+
+    MIDL_STUB_MESSAGE StubMsg;
+    MIDL_STUB_DESC StubDesc;
+    RPC_MESSAGE RpcMessage;
+    IPersist *proxy;
+    HRESULT hr;
+    GUID clsid;
+    void *ptr;
+    LONG ref;
+
+    static const unsigned char fmtstr_ip[] =
+    {
+        FC_IP,
+        FC_CONSTANT_IID,
+        NdrFcLong(0x0000010c),
+        NdrFcShort(0x0000),
+        NdrFcShort(0x0000),
+        0xc0,
+        0x00,
+        0x00,
+        0x00,
+        0x00,
+        0x00,
+        0x00,
+        0x46,
+    };
+
+    CoInitialize(NULL);
+
+    StubDesc = Object_StubDesc;
+    StubDesc.pFormatTypes = fmtstr_ip;
+
+    NdrClientInitializeNew(&RpcMessage, &StubMsg, &StubDesc, 0);
+    StubMsg.BufferLength = 0;
+    NdrInterfacePointerBufferSize(&StubMsg, (unsigned char *)&client_obj.IPersist_iface, fmtstr_ip);
+
+    StubMsg.RpcMsg->Buffer = StubMsg.BufferStart = StubMsg.Buffer = HeapAlloc(GetProcessHeap(), 0, StubMsg.BufferLength);
+    StubMsg.BufferEnd = StubMsg.BufferStart + StubMsg.BufferLength;
+
+    /* server -> client */
+
+    StubMsg.IsClient = 0;
+    my_alloc_called = my_free_called = 0;
+    StubMsg.Buffer = StubMsg.BufferStart;
+    IPersist_AddRef(&server_obj.IPersist_iface);
+    ptr = NdrInterfacePointerMarshall(&StubMsg, (unsigned char *)&server_obj.IPersist_iface, fmtstr_ip);
+    ok(!ptr, "ret %p\n", ptr);
+    ok(server_obj.ref > 2, "got %d references\n", server_obj.ref);
+    ok(!my_alloc_called, "alloc called %d\n", my_alloc_called);
+    ok(!my_free_called, "free called %d\n", my_free_called);
+
+    NdrInterfacePointerFree(&StubMsg, (unsigned char *)&server_obj.IPersist_iface, fmtstr_ip);
+    ok(server_obj.ref > 1, "got %d references\n", server_obj.ref);
+
+    StubMsg.IsClient = 1;
+    my_alloc_called = my_free_called = 0;
+    StubMsg.Buffer = StubMsg.BufferStart;
+    proxy = NULL;
+    ptr = NdrInterfacePointerUnmarshall(&StubMsg, (unsigned char **)&proxy, fmtstr_ip, 0);
+    ok(!ptr, "ret %p\n", ptr);
+    ok(!!proxy, "mem not alloced\n");
+    ok(!my_alloc_called, "alloc called %d\n", my_alloc_called);
+    ok(!my_free_called, "free called %d\n", my_free_called);
+    ok(server_obj.ref > 1, "got %d references\n", server_obj.ref);
+
+    hr = IPersist_GetClassID(proxy, &clsid);
+    ok(hr == S_OK, "got hr %#x\n", hr);
+    ok(IsEqualGUID(&clsid, &IID_IPersist), "wrong clsid %s\n", wine_dbgstr_guid(&clsid));
+
+    ref = IPersist_Release(proxy);
+    ok(ref == 1, "got %d references\n", ref);
+    ok(server_obj.ref == 1, "got %d references\n", server_obj.ref);
+
+    /* An existing interface pointer is released; this is necessary so that an
+     * [in, out] pointer which changes does not leak references. */
+
+    StubMsg.IsClient = 0;
+    my_alloc_called = my_free_called = 0;
+    StubMsg.Buffer = StubMsg.BufferStart;
+    IPersist_AddRef(&server_obj.IPersist_iface);
+    ptr = NdrInterfacePointerMarshall(&StubMsg, (unsigned char *)&server_obj.IPersist_iface, fmtstr_ip);
+    ok(!ptr, "ret %p\n", ptr);
+    ok(server_obj.ref > 2, "got %d references\n", server_obj.ref);
+    ok(!my_alloc_called, "alloc called %d\n", my_alloc_called);
+    ok(!my_free_called, "free called %d\n", my_free_called);
+
+    NdrInterfacePointerFree(&StubMsg, (unsigned char *)&server_obj.IPersist_iface, fmtstr_ip);
+    ok(server_obj.ref > 1, "got %d references\n", server_obj.ref);
+
+    StubMsg.IsClient = 1;
+    my_alloc_called = my_free_called = 0;
+    StubMsg.Buffer = StubMsg.BufferStart;
+    proxy = &client_obj.IPersist_iface;
+    IPersist_AddRef(proxy);
+    ptr = NdrInterfacePointerUnmarshall(&StubMsg, (unsigned char **)&proxy, fmtstr_ip, 0);
+    ok(!ptr, "ret %p\n", ptr);
+    ok(!!proxy && proxy != &client_obj.IPersist_iface, "mem not alloced\n");
+    ok(!my_alloc_called, "alloc called %d\n", my_alloc_called);
+    ok(!my_free_called, "free called %d\n", my_free_called);
+    ok(server_obj.ref > 1, "got %d references\n", server_obj.ref);
+todo_wine
+    ok(client_obj.ref == 1, "got %d references\n", client_obj.ref);
+client_obj.ref = 1;
+
+    hr = IPersist_GetClassID(proxy, &clsid);
+    ok(hr == S_OK, "got hr %#x\n", hr);
+    ok(IsEqualGUID(&clsid, &IID_IPersist), "wrong clsid %s\n", wine_dbgstr_guid(&clsid));
+
+    ref = IPersist_Release(proxy);
+    ok(ref == 1, "got %d references\n", ref);
+    ok(server_obj.ref == 1, "got %d references\n", server_obj.ref);
+
+    /* client -> server */
+
+    StubMsg.IsClient = 1;
+    my_alloc_called = my_free_called = 0;
+    StubMsg.Buffer = StubMsg.BufferStart;
+    IPersist_AddRef(&client_obj.IPersist_iface);
+    ptr = NdrInterfacePointerMarshall(&StubMsg, (unsigned char *)&client_obj.IPersist_iface, fmtstr_ip);
+    ok(!ptr, "ret %p\n", ptr);
+    ok(client_obj.ref > 2, "got %d references\n", client_obj.ref);
+    ok(!my_alloc_called, "alloc called %d\n", my_alloc_called);
+    ok(!my_free_called, "free called %d\n", my_free_called);
+
+    StubMsg.IsClient = 0;
+    my_alloc_called = my_free_called = 0;
+    StubMsg.Buffer = StubMsg.BufferStart;
+    proxy = NULL;
+    ptr = NdrInterfacePointerUnmarshall(&StubMsg, (unsigned char **)&proxy, fmtstr_ip, 0);
+    ok(!ptr, "ret %p\n", ptr);
+    ok(!!proxy, "mem not alloced\n");
+    ok(!my_alloc_called, "alloc called %d\n", my_alloc_called);
+    ok(!my_free_called, "free called %d\n", my_free_called);
+    ok(client_obj.ref > 2, "got %d references\n", client_obj.ref);
+
+    hr = IPersist_GetClassID(proxy, &clsid);
+    ok(hr == S_OK, "got hr %#x\n", hr);
+    ok(IsEqualGUID(&clsid, &IID_IPersist), "wrong clsid %s\n", wine_dbgstr_guid(&clsid));
+
+    ref = IPersist_Release(proxy);
+    ok(client_obj.ref > 1, "got %d references\n", client_obj.ref);
+    ok(ref == client_obj.ref, "expected %d references, got %d\n", client_obj.ref, ref);
+
+    NdrInterfacePointerFree(&StubMsg, (unsigned char *)proxy, fmtstr_ip);
+    ok(client_obj.ref == 1, "got %d references\n", client_obj.ref);
+
+    /* same, but free the interface after calling NdrInterfacePointerFree */
+
+    StubMsg.IsClient = 1;
+    my_alloc_called = my_free_called = 0;
+    StubMsg.Buffer = StubMsg.BufferStart;
+    IPersist_AddRef(&client_obj.IPersist_iface);
+    ptr = NdrInterfacePointerMarshall(&StubMsg, (unsigned char *)&client_obj.IPersist_iface, fmtstr_ip);
+    ok(!ptr, "ret %p\n", ptr);
+    ok(client_obj.ref > 2, "got %d references\n", client_obj.ref);
+    ok(!my_alloc_called, "alloc called %d\n", my_alloc_called);
+    ok(!my_free_called, "free called %d\n", my_free_called);
+
+    StubMsg.IsClient = 0;
+    my_alloc_called = my_free_called = 0;
+    StubMsg.Buffer = StubMsg.BufferStart;
+    proxy = NULL;
+    ptr = NdrInterfacePointerUnmarshall(&StubMsg, (unsigned char **)&proxy, fmtstr_ip, 0);
+    ok(!ptr, "ret %p\n", ptr);
+    ok(!!proxy, "mem not alloced\n");
+    ok(!my_alloc_called, "alloc called %d\n", my_alloc_called);
+    ok(!my_free_called, "free called %d\n", my_free_called);
+    ok(client_obj.ref > 2, "got %d references\n", client_obj.ref);
+
+    NdrInterfacePointerFree(&StubMsg, (unsigned char *)proxy, fmtstr_ip);
+    ok(client_obj.ref > 1, "got %d references\n", client_obj.ref);
+
+    hr = IPersist_GetClassID(proxy, &clsid);
+    ok(hr == S_OK, "got hr %#x\n", hr);
+    ok(IsEqualGUID(&clsid, &IID_IPersist), "wrong clsid %s\n", wine_dbgstr_guid(&clsid));
+
+    ref = IPersist_Release(proxy);
+    ok(ref == 1, "got %d references\n", ref);
+    ok(client_obj.ref == 1, "got %d references\n", client_obj.ref);
+
+    /* An existing interface pointer is *not* released (in fact, it is ignored
+     * and may be invalid). In practice it will always be NULL anyway. */
+
+    StubMsg.IsClient = 1;
+    my_alloc_called = my_free_called = 0;
+    StubMsg.Buffer = StubMsg.BufferStart;
+    IPersist_AddRef(&client_obj.IPersist_iface);
+    ptr = NdrInterfacePointerMarshall(&StubMsg, (unsigned char *)&client_obj.IPersist_iface, fmtstr_ip);
+    ok(!ptr, "ret %p\n", ptr);
+    ok(client_obj.ref > 2, "got %d references\n", client_obj.ref);
+    ok(!my_alloc_called, "alloc called %d\n", my_alloc_called);
+    ok(!my_free_called, "free called %d\n", my_free_called);
+
+    StubMsg.IsClient = 0;
+    my_alloc_called = my_free_called = 0;
+    StubMsg.Buffer = StubMsg.BufferStart;
+    proxy = &server_obj.IPersist_iface;
+    IPersist_AddRef(proxy);
+    ptr = NdrInterfacePointerUnmarshall(&StubMsg, (unsigned char **)&proxy, fmtstr_ip, 0);
+    ok(!ptr, "ret %p\n", ptr);
+    ok(!!proxy && proxy != &server_obj.IPersist_iface, "mem not alloced\n");
+    ok(!my_alloc_called, "alloc called %d\n", my_alloc_called);
+    ok(!my_free_called, "free called %d\n", my_free_called);
+    ok(client_obj.ref > 2, "got %d references\n", client_obj.ref);
+    ok(server_obj.ref == 2, "got %d references\n", server_obj.ref);
+    IPersist_Release(&server_obj.IPersist_iface);
+
+    hr = IPersist_GetClassID(proxy, &clsid);
+    ok(hr == S_OK, "got hr %#x\n", hr);
+    ok(IsEqualGUID(&clsid, &IID_IPersist), "wrong clsid %s\n", wine_dbgstr_guid(&clsid));
+
+    ref = IPersist_Release(proxy);
+    ok(client_obj.ref > 1, "got %d references\n", client_obj.ref);
+    ok(ref == client_obj.ref, "expected %d references, got %d\n", client_obj.ref, ref);
+
+    NdrInterfacePointerFree(&StubMsg, (unsigned char *)proxy, fmtstr_ip);
+    ok(client_obj.ref == 1, "got %d references\n", client_obj.ref);
+
+    CoUninitialize();
+}
+
 static void test_fullpointer_xlat(void)
 {
     PFULL_PTR_XLAT_TABLES pXlatTables;
@@ -2635,6 +2910,7 @@ START_TEST( ndr_marshall )
     test_simple_types();
     test_nontrivial_pointer_types();
     test_simple_struct();
+    test_iface_ptr();
     test_fullpointer_xlat();
     test_client_init();
     test_server_init();
-- 
2.19.1




More information about the wine-devel mailing list