[2/4] widl: Handle pointers in unions

Dan Hipschman dsh at linux.ucla.edu
Thu May 24 19:48:39 CDT 2007


This patch unifies write_pointers with write_embedded_types, and handles
pointers in unions.  Includes tests.

This gets us past another oaidl.idl error, however the one hiding behind
it is a segfault.  That's fixed by the forth patch in this series.  Note
that this patch doesn't add the segfault.  It's always been there, widl
just never got a chance to get that far along.  It's also only when
generating the proxy file.  The wine build is still fine.

---
 dlls/rpcrt4/tests/server.c         |    8 ++
 dlls/rpcrt4/tests/server.idl       |    1 +
 dlls/rpcrt4/tests/server_defines.h |    1 +
 tools/widl/typegen.c               |  135 +++++++++++++++++-------------------
 4 files changed, 74 insertions(+), 71 deletions(-)

diff --git a/dlls/rpcrt4/tests/server.c b/dlls/rpcrt4/tests/server.c
index 016088a..0a628c1 100644
--- a/dlls/rpcrt4/tests/server.c
+++ b/dlls/rpcrt4/tests/server.c
@@ -24,6 +24,7 @@
 #include "server_defines.h"
 
 #include <stdio.h>
+#include <stdlib.h>
 
 #define PORT "4114"
 #define PIPE "\\pipe\\wine_rpcrt4_test"
@@ -147,6 +148,7 @@ s_square_sun(sun_t *sun)
   case SUN_I: return sun->u.i * sun->u.i;
   case SUN_F1:
   case SUN_F2: return sun->u.f * sun->u.f;
+  case SUN_PI: return (*sun->u.pi) * (*sun->u.pi);
   default:
     return 0.0;
   }
@@ -270,6 +272,7 @@ static void
 union_tests(void)
 {
   sun_t sun;
+  int i;
 
   sun.s = SUN_I;
   sun.u.i = 9;
@@ -282,6 +285,11 @@ union_tests(void)
   sun.s = SUN_F2;
   sun.u.f = -2.0;
   ok(square_sun(&sun) == 4.0, "RPC square_sun\n");
+
+  sun.s = SUN_PI;
+  sun.u.pi = &i;
+  i = 11;
+  ok(square_sun(&sun) == 121.0, "RPC square_sun\n");
 }
 
 static void
diff --git a/dlls/rpcrt4/tests/server.idl b/dlls/rpcrt4/tests/server.idl
index e6f27e7..064517e 100644
--- a/dlls/rpcrt4/tests/server.idl
+++ b/dlls/rpcrt4/tests/server.idl
@@ -61,6 +61,7 @@ interface IServer
     {
       [case(SUN_I)] int i;
       [case(SUN_F1, SUN_F2)] float f;
+      [case(SUN_PI)] int *pi;
     } u;
 
     int s;
diff --git a/dlls/rpcrt4/tests/server_defines.h b/dlls/rpcrt4/tests/server_defines.h
index 91f621d..ac94ef5 100644
--- a/dlls/rpcrt4/tests/server_defines.h
+++ b/dlls/rpcrt4/tests/server_defines.h
@@ -22,3 +22,4 @@
 #define SUN_I 10
 #define SUN_F1 -2
 #define SUN_F2 7
+#define SUN_PI 399
diff --git a/tools/widl/typegen.c b/tools/widl/typegen.c
index dbd47c9..4c2833d 100644
--- a/tools/widl/typegen.c
+++ b/tools/widl/typegen.c
@@ -62,7 +62,9 @@ struct expr_eval_routine
 static size_t type_memsize(const type_t *t, const array_dims_t *array, unsigned int *align);
 static size_t fields_memsize(const var_list_t *fields, unsigned int *align);
 static size_t write_struct_tfs(FILE *file, type_t *type, const char *name, unsigned int *tfsoff);
-static void write_embedded_types(FILE *file, const type_t *type, unsigned int *tfsoff);
+static int write_embedded_types(FILE *file, const attr_list_t *attrs, type_t *type,
+                                const char *name, const array_dims_t *array, int level,
+                                unsigned int *tfsoff);
 
 const char *string_of_type(unsigned char type)
 {
@@ -802,63 +804,6 @@ static int has_known_tfs(const type_t *type)
     return type->typestring_offset || is_base_type(type->type);
 }
 
-static int write_pointers(FILE *file, const attr_list_t *attrs,
-                          type_t *type, const char *name,
-                          const array_dims_t *array, int level,
-                          unsigned int *typestring_offset)
-{
-    const var_t *v;
-
-    /* don't generate a pointer for first-level arrays since we want to
-    * descend into them to write their pointers, not stop here */
-    if ((level == 0 || !is_ptr(type)) && is_array_type(attrs, type, array))
-    {
-        return write_pointers(file, NULL, type, name, NULL, level + 1, typestring_offset);
-    }
-    else if (is_ptr(type))
-    {
-        type_t *ref = type->ref;
-
-        if (!has_known_tfs(ref))
-        {
-            if (is_ptr(ref))
-            {
-                write_pointers(file, attrs, ref, name, array, level + 1,
-                               typestring_offset);
-            }
-            else if (is_struct(ref->type))
-            {
-                write_struct_tfs(file, ref, name, typestring_offset);
-            }
-            else
-            {
-                error("write_pointers: type format string unknown for %s (0x%02x)\n",
-                      name, ref->type);
-            }
-        }
-
-        /* top-level pointers are handled by write_pointer_description */
-        if (1 < level)
-            write_pointer_tfs(file, type, typestring_offset);
-
-        return 1;
-    }
-    else if (is_struct(type->type))
-    {
-        int pointers_written = 0;
-        if (type->fields)
-        {
-            LIST_FOR_EACH_ENTRY( v, type->fields, const var_t, entry )
-                pointers_written += write_pointers(file, v->attrs, v->type,
-                                                   v->name, v->array,
-                                                   level + 1,
-                                                   typestring_offset);
-        }
-        return pointers_written;
-    }
-    else return 0;
-}
-
 static size_t write_pointer_description(FILE *file, const attr_list_t *attrs,
                                         type_t *type, size_t mem_offset,
                                         const array_dims_t *array, int level,
@@ -1023,7 +968,7 @@ static size_t write_array_tfs(FILE *file, const attr_list_t *attrs,
         const expr_t *dim = array ? LIST_ENTRY( list_head( array ), expr_t, entry ) : NULL;
         int has_pointer = 0;
 
-        if (write_pointers(file, attrs, type, name, array, 0, typestring_offset) > 0)
+        if (write_embedded_types(file, attrs, type, name, array, 0, typestring_offset))
             has_pointer = 1;
 
         start_offset = *typestring_offset;
@@ -1290,7 +1235,7 @@ static size_t write_struct_tfs(FILE *file, type_t *type,
                   name, USHRT_MAX, total_size - USHRT_MAX);
 
         if (type->type == RPC_FC_PSTRUCT)
-            write_pointers(file, NULL, type, name, NULL, 0, typestring_offset);
+            write_embedded_types(file, NULL, type, name, NULL, 0, typestring_offset);
 
         start_offset = *typestring_offset;
         type->typestring_offset = start_offset;
@@ -1333,7 +1278,7 @@ static size_t write_struct_tfs(FILE *file, type_t *type,
         current_structure = NULL;
 
         if (type->type == RPC_FC_CPSTRUCT)
-            write_pointers(file, NULL, type, name, NULL, 0, typestring_offset);
+            write_embedded_types(file, NULL, type, name, NULL, 0, typestring_offset);
 
         start_offset = *typestring_offset;
         type->typestring_offset = start_offset;
@@ -1385,7 +1330,8 @@ static size_t write_struct_tfs(FILE *file, type_t *type,
                                            typestring_offset);
         current_structure = NULL;
 
-        has_pointers = write_pointers(file, NULL, type, name, NULL, 0, typestring_offset);
+        has_pointers = write_embedded_types(file, NULL, type, name, NULL, 0,
+                                            typestring_offset);
 
         start_offset = *typestring_offset;
         type->typestring_offset = start_offset;
@@ -1422,7 +1368,7 @@ static size_t write_struct_tfs(FILE *file, type_t *type,
             error("structure size for %s exceeds %d bytes by %d bytes\n",
                   name, USHRT_MAX, total_size - USHRT_MAX);
 
-        write_embedded_types(file, type, typestring_offset);
+        write_embedded_types(file, NULL, type, name, NULL, 0, typestring_offset);
 
         start_offset = *typestring_offset;
         print_file(file, 0, "/* %d */\n", start_offset);
@@ -1489,7 +1435,7 @@ static void write_branch_type(FILE *file, const type_t *t, unsigned int *tfsoff)
     }
     else if (t->typestring_offset)
     {
-        short reloff = t->typestring_offset - (*tfsoff + 2);
+        short reloff = t->typestring_offset - *tfsoff;
         print_file(file, 2, "NdrFcShort(0x%x),\t/* Offset= %d (%d) */\n",
                    reloff, reloff, t->typestring_offset);
     }
@@ -1499,7 +1445,8 @@ static void write_branch_type(FILE *file, const type_t *t, unsigned int *tfsoff)
     *tfsoff += 2;
 }
 
-static size_t write_union_tfs(FILE *file, type_t *type, unsigned int *tfsoff)
+static size_t write_union_tfs(FILE *file, type_t *type, const char *name,
+                              unsigned int *tfsoff)
 {
     unsigned int align = 0;
     unsigned int start_offset;
@@ -1510,6 +1457,9 @@ static size_t write_union_tfs(FILE *file, type_t *type, unsigned int *tfsoff)
     short nodeftype = 0xffff;
     var_t *f;
 
+    /* use a level of 1 so pointers always get written */
+    write_embedded_types(file, NULL, type, name, NULL, 1, tfsoff);
+
     if (fields) LIST_FOR_EACH_ENTRY(f, fields, var_t, entry)
     {
         expr_list_t *cases = get_attrp(f->attrs, ATTR_CASE);
@@ -1674,7 +1624,7 @@ static size_t write_typeformatstring_var(FILE *file, int indent, const func_t *f
             return write_struct_tfs(file, type, var->name, typeformat_offset);
         case RPC_FC_ENCAPSULATED_UNION:
         case RPC_FC_NON_ENCAPSULATED_UNION:
-            return write_union_tfs(file, type, typeformat_offset);
+            return write_union_tfs(file, type, var->name, typeformat_offset);
         case RPC_FC_IGNORE:
         case RPC_FC_BIND_PRIMITIVE:
             /* nothing to do */
@@ -1743,9 +1693,12 @@ static void clear_tfsoff(type_t *type)
     }
 }
 
-static void write_embedded_types(FILE *file, const type_t *type, unsigned int *tfsoff)
+static int write_embedded_types(FILE *file, const attr_list_t *attrs, type_t *type,
+                                const char *name, const array_dims_t *array,
+                                int level, unsigned int *tfsoff)
 {
     var_list_t *fields = type->fields;
+    int retmask = 0;
     size_t offset = 0;
     var_t *f;
 
@@ -1753,13 +1706,13 @@ static void write_embedded_types(FILE *file, const type_t *type, unsigned int *t
     {
         unsigned int align = 0;
         type_t *ft = f->type;
-        size_t corroff;
 
         if (ft->type == RPC_FC_NON_ENCAPSULATED_UNION)
         {
             expr_t *swexp = get_attrp(f->attrs, ATTR_SWITCHIS);
             const char *swname;
             var_t *swvar;
+            size_t corroff;
             unsigned char corrdesc, op = 0;
             short creloff, ureloff;
 
@@ -1770,7 +1723,7 @@ static void write_embedded_types(FILE *file, const type_t *type, unsigned int *t
                       f->name);
 
             if (ft->typestring_offset == 0)
-                write_union_tfs(file, ft, tfsoff);
+                write_union_tfs(file, ft, f->name, tfsoff);
 
             swname = swexp->u.sval;
             corroff = field_offset(type, swname, &swvar);
@@ -1790,12 +1743,52 @@ static void write_embedded_types(FILE *file, const type_t *type, unsigned int *t
                        ureloff, ureloff, ft->typestring_offset);
             *tfsoff += 8;
         }
-        else if (!is_base_type(ft->type))
-            error("write_embedded_types: unknown type (0x%x)\n", ft->type);
+        else
+            retmask |= write_embedded_types(file, attrs, ft, f->name, array,
+                                            level + 1, tfsoff);
 
         /* FIXME: this doesn't take alignment/padding into account */
         offset += type_memsize(ft, NULL, &align);
     }
+    /* don't generate a pointer for first-level arrays since we want to
+       descend into them to write their pointers, not stop here */
+    else if ((level == 0 || !is_ptr(type)) && is_array_type(attrs, type, array))
+    {
+        return write_embedded_types(file, NULL, type, name, NULL, level + 1, tfsoff);
+    }
+    else if (is_ptr(type))
+    {
+        type_t *ref = type->ref;
+
+        if (!has_known_tfs(ref))
+        {
+            if (is_ptr(ref))
+            {
+                retmask |= write_embedded_types(file, attrs, ref, name, array,
+                                                level + 1, tfsoff);
+            }
+            else if (is_struct(ref->type))
+            {
+                write_struct_tfs(file, ref, name, tfsoff);
+            }
+            else
+            {
+                error("write_embedded_types: type format string unknown for %s (0x%x)\n",
+                      name, ref->type);
+            }
+        }
+
+        /* top-level pointers are handled inline */
+        if (1 < level)
+            write_pointer_tfs(file, type, tfsoff);
+
+        retmask |= 1;
+    }
+    else if (!is_base_type(type->type))
+        error("write_embedded_types: unknown embedded type for %s (0x%x)\n",
+              name, type->type);
+
+    return retmask;
 }
 
 static void clear_all_tfsoffs(const ifref_list_t *ifaces)



More information about the wine-patches mailing list