widl: Fix problems with variable-size user types.

Dan Hipschman dsh at linux.ucla.edu
Fri Oct 19 17:30:12 CDT 2007


This patch fixes two problems with user-marshal types.  First, the
type sizes for the user type and wire type were outupt in the wrong
order, so they were essentially reversed.  Second, if the size of the
wire type is variable (e.g., a conformant struct), its size should be
listed as zero.  This patch almost enables us to use widl to generate
oaidl_p.c.  The only problems left are implementing
IPropertyBag_Read_Stub, and then tweaking the Makefiles.  When I
mentioned this yesterday and said three tests in tmarshal.c still
failed, I had only fixed the second user-marshal problem.  With this
patch all the oleaut32 tests pass, as do the ole32 tests, even without
additional error/warning/fixme messages:

[tests]$ WINEDEBUG=warn+heap make -j1 check >/tmp/midl_oleaut32.log 2>&1
[tests]$ diff /tmp/[mw]idl_oleaut32.log

I also ran winetest a number of times with no new failures
consistently showing up (there always seems to be some noise).

---
 dlls/rpcrt4/tests/server.c   |   48 ++++++++++++++++++++++++++++++++++++++++++
 dlls/rpcrt4/tests/server.idl |    9 +++++++
 tools/widl/typegen.c         |   22 +++++++++++++++++-
 3 files changed, 77 insertions(+), 2 deletions(-)

diff --git a/dlls/rpcrt4/tests/server.c b/dlls/rpcrt4/tests/server.c
index 97f2e23..d0f4eef 100644
--- a/dlls/rpcrt4/tests/server.c
+++ b/dlls/rpcrt4/tests/server.c
@@ -459,6 +459,18 @@ s_make_pyramid_doub_carr(unsigned char n, doub_carr_t **dc)
   *dc = t;
 }
 
+unsigned
+s_hash_bstr(bstr_t b)
+{
+  short n = b[-1];
+  short *s = b;
+  unsigned hash = 0;
+  short i;
+  for (i = 0; i < n; ++i)
+    hash = 5 * hash + (unsigned) s[i];
+  return hash;
+}
+
 void
 s_stop(void)
 {
@@ -744,6 +756,38 @@ us_t_UserFree(ULONG *flags, us_t *pus)
   HeapFree(GetProcessHeap(), 0, pus->x);
 }
 
+ULONG __RPC_USER
+bstr_t_UserSize(ULONG *flags, ULONG start, bstr_t *b)
+{
+  return start + FIELD_OFFSET(wire_bstr_t, data[(*b)[-1]]);
+}
+
+unsigned char * __RPC_USER
+bstr_t_UserMarshal(ULONG *flags, unsigned char *buffer, bstr_t *b)
+{
+  wire_bstr_t *wb = (wire_bstr_t *) buffer;
+  wb->n = (*b)[-1];
+  memcpy(&wb->data, *b, wb->n * sizeof wb->data[0]);
+  return buffer + FIELD_OFFSET(wire_bstr_t, data[wb->n]);
+}
+
+unsigned char * __RPC_USER
+bstr_t_UserUnmarshal(ULONG *flags, unsigned char *buffer, bstr_t *b)
+{
+  wire_bstr_t *wb = (wire_bstr_t *) buffer;
+  short *data = HeapAlloc(GetProcessHeap(), 0, (wb->n + 1) * sizeof *data);
+  data[0] = wb->n;
+  memcpy(&data[1], wb->data, wb->n * sizeof data[1]);
+  *b = &data[1];
+  return buffer + FIELD_OFFSET(wire_bstr_t, data[wb->n]);
+}
+
+void __RPC_USER
+bstr_t_UserFree(ULONG *flags, bstr_t *b)
+{
+  HeapFree(GetProcessHeap(), 0, &((*b)[-1]));
+}
+
 static void
 pointer_tests(void)
 {
@@ -754,6 +798,8 @@ pointer_tests(void)
   int *pa[4];
   puints_t pus;
   cpuints_t cpus;
+  short bstr_data[] = { 5, 'H', 'e', 'l', 'l', 'o' };
+  bstr_t bstr = &bstr_data[1];
 
   ok(test_list_length(list) == 3, "RPC test_list_length\n");
   ok(square_puint(p1) == 121, "RPC square_puint\n");
@@ -794,6 +840,8 @@ pointer_tests(void)
   pa[3] = &a[3];
   ok(sum_pcarr(pa, 4) == 10, "RPC sum_pcarr\n");
 
+  ok(hash_bstr(bstr) == s_hash_bstr(bstr), "RPC hash_bstr_data\n");
+
   free_list(list);
 }
 
diff --git a/dlls/rpcrt4/tests/server.idl b/dlls/rpcrt4/tests/server.idl
index 807bf44..fa1ea15 100644
--- a/dlls/rpcrt4/tests/server.idl
+++ b/dlls/rpcrt4/tests/server.idl
@@ -281,5 +281,14 @@ cpp_quote("#endif")
   int sum_doub_carr(doub_carr_t *dc);
   void make_pyramid_doub_carr(unsigned char n, [out] doub_carr_t **dc);
 
+  typedef struct
+  {
+    short n;
+    [size_is(n)] short data[];
+  } wire_bstr_t;
+
+  typedef [wire_marshal(wire_bstr_t)] short *bstr_t;
+  unsigned hash_bstr(bstr_t s);
+
   void stop(void);
 }
diff --git a/tools/widl/typegen.c b/tools/widl/typegen.c
index 6f194b7..dd21fe4 100644
--- a/tools/widl/typegen.c
+++ b/tools/widl/typegen.c
@@ -907,13 +907,31 @@ static int processed(const type_t *type)
     return type->typestring_offset && !type->tfswrite;
 }
 
+static int user_type_has_variable_size(const type_t *t)
+{
+    if (is_ptr(t))
+        return TRUE;
+    else
+        switch (t->type)
+        {
+        case RPC_FC_PSTRUCT:
+        case RPC_FC_CSTRUCT:
+        case RPC_FC_CPSTRUCT:
+        case RPC_FC_CVSTRUCT:
+            return TRUE;
+        }
+    /* Note: Since this only applies to user types, we can't have a conformant
+       array here, and strings should get filed under pointer in this case.  */
+    return FALSE;
+}
+
 static void write_user_tfs(FILE *file, type_t *type, unsigned int *tfsoff)
 {
     unsigned int start, absoff, flags;
     unsigned int align = 0, ualign = 0;
     const char *name;
     type_t *utype = get_user_type(type, &name);
-    size_t usize = type_memsize(utype, &ualign);
+    size_t usize = user_type_has_variable_size(utype) ? 0 : type_memsize(utype, &ualign);
     size_t size = type_memsize(type, &align);
     unsigned short funoff = user_type_offset(name);
     short reloff;
@@ -949,8 +967,8 @@ static void write_user_tfs(FILE *file, type_t *type, unsigned int *tfsoff)
     print_file(file, 2, "0x%x,\t/* Alignment= %d, Flags= %02x */\n",
                flags | (align - 1), align - 1, flags);
     print_file(file, 2, "NdrFcShort(0x%hx),\t/* Function offset= %hu */\n", funoff, funoff);
-    print_file(file, 2, "NdrFcShort(0x%lx),\t/* %lu */\n", usize, usize);
     print_file(file, 2, "NdrFcShort(0x%lx),\t/* %lu */\n", size, size);
+    print_file(file, 2, "NdrFcShort(0x%lx),\t/* %lu */\n", usize, usize);
     *tfsoff += 8;
     reloff = absoff - *tfsoff;
     print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%lu) */\n", reloff, reloff, absoff);



More information about the wine-patches mailing list