widl [4/4]: Detect conformant arrays of user types correctly.

Dan Hipschman dsh at linux.ucla.edu
Wed Oct 17 20:06:26 CDT 2007


This patch fixes a crash in the oleaut32 tmarshal test when using widl's
oaidl_p.c.  The problem had to do with conformant arrays of user types.
These weren't being detecting correctly, and they weren't included in the
pointer description for complex structures.  New tests pass under wine
and on windows.  I also reran the ole32 and oleaut32 tests.  Nothing
fails.

I have one more patch in my queue which isn't quite ready to send in today
since I don't have good tests for it.  However, with it, I can use widl's
oaidl_p.c without crashing the tmarshal test (it still has three failures,
though):

    tmarshal: 74 tests executed (0 marked as todo, 3 failures), 0 skipped.

So, anyway, that's progress.  :-)

---
 dlls/rpcrt4/tests/server.c   |   54 ++++++++++++++++++++++++++++++++++++++++++
 dlls/rpcrt4/tests/server.idl |   16 ++++++++++++
 tools/widl/header.c          |    4 ++-
 tools/widl/parser.y          |   41 ++++++++++++++------------------
 tools/widl/typegen.c         |   16 ++++++++++++
 5 files changed, 107 insertions(+), 24 deletions(-)

diff --git a/dlls/rpcrt4/tests/server.c b/dlls/rpcrt4/tests/server.c
index d8ecff0..97f2e23 100644
--- a/dlls/rpcrt4/tests/server.c
+++ b/dlls/rpcrt4/tests/server.c
@@ -48,6 +48,14 @@ midl_user_free(void __RPC_FAR *p)
   free(p);
 }
 
+static char *
+xstrdup(const char *s)
+{
+  char *d = HeapAlloc(GetProcessHeap(), 0, strlen(s) + 1);
+  strcpy(d, s);
+  return d;
+}
+
 int
 s_int_return(void)
 {
@@ -264,6 +272,26 @@ s_square_puint(puint_t p)
 }
 
 int
+s_sum_puints(puints_t *p)
+{
+  int sum = 0;
+  int i;
+  for (i = 0; i < p->n; ++i)
+    sum += atoi(p->ps[i]);
+  return sum;
+}
+
+int
+s_sum_cpuints(cpuints_t *p)
+{
+  int sum = 0;
+  int i;
+  for (i = 0; i < p->n; ++i)
+    sum += atoi(p->ps[i]);
+  return sum;
+}
+
+int
 s_dot_copy_vectors(vector_t u, vector_t v)
 {
   return u.x * v.x + u.y * v.y + u.z * v.z;
@@ -724,9 +752,35 @@ pointer_tests(void)
   test_list_t *list = make_list(make_list(make_list(null_list())));
   test_us_t tus = {{p1}};
   int *pa[4];
+  puints_t pus;
+  cpuints_t cpus;
 
   ok(test_list_length(list) == 3, "RPC test_list_length\n");
   ok(square_puint(p1) == 121, "RPC square_puint\n");
+  pus.n = 4;
+  pus.ps = HeapAlloc(GetProcessHeap(), 0, pus.n * sizeof pus.ps[0]);
+  pus.ps[0] = xstrdup("5");
+  pus.ps[1] = xstrdup("6");
+  pus.ps[2] = xstrdup("7");
+  pus.ps[3] = xstrdup("8");
+  ok(sum_puints(&pus) == 26, "RPC sum_puints\n");
+  HeapFree(GetProcessHeap(), 0, pus.ps[0]);
+  HeapFree(GetProcessHeap(), 0, pus.ps[1]);
+  HeapFree(GetProcessHeap(), 0, pus.ps[2]);
+  HeapFree(GetProcessHeap(), 0, pus.ps[3]);
+  HeapFree(GetProcessHeap(), 0, pus.ps);
+  cpus.n = 4;
+  cpus.ps = HeapAlloc(GetProcessHeap(), 0, cpus.n * sizeof cpus.ps[0]);
+  cpus.ps[0] = xstrdup("5");
+  cpus.ps[1] = xstrdup("6");
+  cpus.ps[2] = xstrdup("7");
+  cpus.ps[3] = xstrdup("8");
+  ok(sum_cpuints(&cpus) == 26, "RPC sum_puints\n");
+  HeapFree(GetProcessHeap(), 0, cpus.ps[0]);
+  HeapFree(GetProcessHeap(), 0, cpus.ps[1]);
+  HeapFree(GetProcessHeap(), 0, cpus.ps[2]);
+  HeapFree(GetProcessHeap(), 0, cpus.ps[3]);
+  HeapFree(GetProcessHeap(), 0, cpus.ps);
   ok(square_test_us(&tus) == 121, "RPC square_test_us\n");
 
   pa[0] = &a[0];
diff --git a/dlls/rpcrt4/tests/server.idl b/dlls/rpcrt4/tests/server.idl
index 6233a1f..807bf44 100644
--- a/dlls/rpcrt4/tests/server.idl
+++ b/dlls/rpcrt4/tests/server.idl
@@ -153,6 +153,22 @@ cpp_quote("#endif")
 
   typedef [wire_marshal(int)] void *puint_t;
   int square_puint(puint_t p);
+
+  typedef struct
+  {
+    [size_is(n)] puint_t *ps;
+    int n;
+  } puints_t;
+
+  /* Same thing as puints_t, but make it complex (needs padding).  */
+  typedef struct
+  {
+    [size_is(n)] puint_t *ps;
+    char n;
+  } cpuints_t;
+
+  int sum_puints(puints_t *p);
+  int sum_cpuints(cpuints_t *p);
   int dot_copy_vectors(vector_t u, vector_t v);
 
   typedef struct wire_us *wire_us_t;
diff --git a/tools/widl/header.c b/tools/widl/header.c
index 2643f49..8de9b9f 100644
--- a/tools/widl/header.c
+++ b/tools/widl/header.c
@@ -101,7 +101,9 @@ int is_void(const type_t *t)
 
 int is_conformant_array(const type_t *t)
 {
-    return t->type == RPC_FC_CARRAY || t->type == RPC_FC_CVARRAY;
+    return t->type == RPC_FC_CARRAY
+        || t->type == RPC_FC_CVARRAY
+        || (t->type == RPC_FC_BOGUS_ARRAY && t->size_is);
 }
 
 void write_guid(FILE *f, const char *guid_prefix, const char *name, const UUID *uuid)
diff --git a/tools/widl/parser.y b/tools/widl/parser.y
index 96e9891..6a93995 100644
--- a/tools/widl/parser.y
+++ b/tools/widl/parser.y
@@ -1434,24 +1434,24 @@ static void set_type(var_t *v, type_t *type, int ptr_level, array_dims_t *arr,
   if (is_array(v->type))
   {
     const type_t *rt = v->type->ref;
-    switch (rt->type)
-    {
-    case RPC_FC_BOGUS_STRUCT:
-    case RPC_FC_NON_ENCAPSULATED_UNION:
-    case RPC_FC_ENCAPSULATED_UNION:
-    case RPC_FC_ENUM16:
+    if (is_user_type(rt))
       v->type->type = RPC_FC_BOGUS_ARRAY;
-      break;
-    /* FC_RP should be above, but widl overuses these, and will break things.  */
-    case RPC_FC_UP:
-    case RPC_FC_RP:
-      if (rt->ref->type == RPC_FC_IP)
-        v->type->type = RPC_FC_BOGUS_ARRAY;
-      break;
-    default:
-      if (is_user_type(rt))
-        v->type->type = RPC_FC_BOGUS_ARRAY;
-    }
+    else
+      switch (rt->type)
+        {
+        case RPC_FC_BOGUS_STRUCT:
+        case RPC_FC_NON_ENCAPSULATED_UNION:
+        case RPC_FC_ENCAPSULATED_UNION:
+        case RPC_FC_ENUM16:
+          v->type->type = RPC_FC_BOGUS_ARRAY;
+          break;
+          /* FC_RP should be above, but widl overuses these, and will break things.  */
+        case RPC_FC_UP:
+        case RPC_FC_RP:
+          if (rt->ref->type == RPC_FC_IP)
+            v->type->type = RPC_FC_BOGUS_ARRAY;
+          break;
+        }
   }
 }
 
@@ -1859,6 +1859,7 @@ static int get_struct_type(var_list_t *fields)
     case RPC_FC_OP:
     case RPC_FC_CARRAY:
     case RPC_FC_CVARRAY:
+    case RPC_FC_BOGUS_ARRAY:
       has_pointer = 1;
       break;
 
@@ -1897,15 +1898,9 @@ static int get_struct_type(var_list_t *fields)
       /* fallthru - treat it as complex */
 
     /* as soon as we see one of these these members, it's bogus... */
-    case RPC_FC_IP:
     case RPC_FC_ENCAPSULATED_UNION:
     case RPC_FC_NON_ENCAPSULATED_UNION:
-    case RPC_FC_TRANSMIT_AS:
-    case RPC_FC_REPRESENT_AS:
-    case RPC_FC_PAD:
-    case RPC_FC_EMBEDDED_COMPLEX:
     case RPC_FC_BOGUS_STRUCT:
-    case RPC_FC_BOGUS_ARRAY:
       return RPC_FC_BOGUS_STRUCT;
     }
   }
diff --git a/tools/widl/typegen.c b/tools/widl/typegen.c
index 53ec78c..2245524 100644
--- a/tools/widl/typegen.c
+++ b/tools/widl/typegen.c
@@ -1744,6 +1744,22 @@ static size_t write_struct_tfs(FILE *file, type_t *type,
             type_t *ft = f->type;
             if (is_ptr(ft))
                 write_pointer_tfs(file, ft, tfsoff);
+            else if (!ft->declarray && is_conformant_array(ft))
+            {
+                unsigned int absoff = ft->typestring_offset;
+                short reloff = absoff - (*tfsoff + 2);
+                int ptr_type = get_attrv(f->attrs, ATTR_POINTERTYPE);
+                /* FIXME: We need to store pointer attributes for arrays
+                   so we don't lose pointer_default info.  */
+                if (ptr_type == 0)
+                    ptr_type = RPC_FC_UP;
+                print_file(file, 0, "/* %d */\n", *tfsoff);
+                print_file(file, 2, "0x%x, 0x0,\t/* %s */\n", ptr_type,
+                           string_of_type(ptr_type));
+                print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
+                           reloff, reloff, absoff);
+                *tfsoff += 4;
+            }
         }
         if (type->ptrdesc == *tfsoff)
             type->ptrdesc = 0;



More information about the wine-patches mailing list