[C2hs] {# sizeof #} hook going wrong for cases of structs with embeded arrays.

Duncan Coutts duncan.coutts at worc.ox.ac.uk
Sat Apr 29 10:28:15 EDT 2006


c2hs is calculating the sizeof glib's GValue structure incorrectly (this
led to a nasty bug).

GValue is defined like this:

struct _GValue
{
  /*< private >*/
  GType         g_type;

  /* public for GTypeValueTable methods */
  union {
    gint        v_int;
    guint       v_uint;
    glong       v_long;
    gulong      v_ulong;
    gint64      v_int64;
    guint64     v_uint64;
    gfloat      v_float;
    gdouble     v_double;
    gpointer    v_pointer;
  } data[2];
};

We used to use this code:


allocaGValue :: (GValue -> IO b) -> IO b
allocaGValue body =
  allocaBytes {# sizeof GValue #} $ \gvPtr -> do
  ...

but we eventually discovered that {# sizeof GValue #} was giving us the
wrong value, I think it was 8. The right value should be 8+8+4=20.

Our current workaround is:

allocaGValue :: (GValue -> IO b) -> IO b
allocaGValue body =
  -- c2hs is broken in that it can't handle arrays of compound arrays in the
  -- sizeof hook
  allocaBytes ({# sizeof GType #}+ 2* {# sizeof guint64 #}) $ \gvPtr -> do


Axel also added this temporary hack so that at least c2hs would report
an error rather the giving the wrong answer:

--- ../build/gtk2hs-0.9.10/tools/c2hs/c/CTrav.hs        2004-11-21 21:05:27.000000000 +0000
+++ ../build/gtk2hs/tools/c2hs/c/CTrav.hs       2006-04-25 18:53:10.000000000 +0100
@@ -73,7 +73,7 @@
              --
              isTypedef, simplifyDecl, declrFromDecl, declrNamed,
              declaredDeclr, declaredName, structMembers, expandDecl,
-             structName, enumName, tagName, isPtrDeclr, dropPtrDeclr,
+             structName, enumName, tagName, isArrDeclr, isPtrDeclr, dropPtrDeclr,
              isPtrDecl, isFunDeclr, structFromDecl, funResultAndArgs,
              chaseDecl, findAndChaseDecl, checkForAlias,
              checkForOneAliasName, lookupEnum, lookupStructUnion,
@@ -537,6 +537,16 @@
 isPtrDeclr (CFunDeclr declr _ _         _)  = isPtrDeclr declr
 isPtrDeclr _                                = False

+-- checks whether the given declarator defines an object that is an array of
+-- some other type (EXPORTED)
+--
+-- * difference between arrays and pure pointers is important for size
+--   calculations
+--
+isArrDeclr                                 :: CDeclr -> Bool
+isArrDeclr (CArrDeclr declr _           _)  = True
+isArrDeclr _                                = False
+
 -- drops the first pointer level from the given declarator (EXPORTED)
 --
 -- * the declarator must declare a pointer object

--- ../build/gtk2hs-0.9.10/tools/c2hs/gen/GenBind.hs    2005-10-17 21:41:30.000000000 +0100
+++ ../build/gtk2hs/tools/c2hs/gen/GenBind.hs   2006-04-25 18:53:10.000000000 +0100
@@ -1665,6 +1667,8 @@
 -- * we make use of the assertion that `extractCompType' can only return a
 --   `DefinedET' when the declaration is a pointer declaration
 --
+sizeAlignOf (CDecl specs [(Just declr, _, size)] ats) | isArrDeclr declr =
+  interr $ "sizeAlignOf: calculating size of constant array not supported."
 sizeAlignOf cdecl  =
   do
     ct <- extractCompType cdecl


So, that's the temporary solution. Of course it'd be better if we could
actually calculate this struct size.

This issue of struct sizes (and alignments) is probably an area that
needs more testing (and on other arches since eg MS packs bit-fields
differently). Perhaps we could write a prog that scans a header file and
generates a .chs and .hsc file with {# sizeof #} hooks for every
structure. Then we could compare the two (with various headers and on
various platforms) and see where the remaining issues are. Using .hsc as
a reference would be the right thing here because hsc2hs uses gcc to
find the struct size. That same kind of test would also do for struct
member offsets.

Duncan



More information about the C2hs mailing list