RE: function in glib/gqueue.c relies on undefined behavour?



In order to support varargs ('...', http://en.wikipedia.org/wiki/Stdarg.h) C compilers put function call arguments backwards on the stack. This allows functions that don't care about extra arguments to simply not offset back far enough on the stack to notice them. No modern C compiler excludes support for varargs and glib relies on varargs anyway. So its not really an issue.

Thanks,
Kevin
________________________________________
From: gtk-devel-list-bounces gnome org [gtk-devel-list-bounces gnome org] On Behalf Of Giovanni Gherdovich [g gherdovich gmail com]
Sent: Monday, December 31, 2012 9:02 AM
To: gtk-devel-list gnome org
Subject: function in glib/gqueue.c relies on undefined behavour?

Hi all,

I stumbled upon the implementation of the function
g_queue_free_full from glib/gqueue.c and there is
something I don't understand:

it takes a unary function as input, i.e.
something of type

void (*) (void *)

and forward it (to the function g_queue_foreach)
as a binary function, by casting it to the type

void (*) (void *, void *)

For the records, the second argument
(which is meant to be "discarded", I guess)
gets the value NULL.

At first sight, I would have imagined that
this is not valid C code, but lives in the gray land
of indefined behaviours;
you can't give two arguments to a function that requires only one!
But it compiles, and work as expected (the second arg
is actually ignored).

Am I missing something?

Here a code snippet the resume the situation;
it is taken from glib/gqueue.c and glib/gtypes.h.
It doesn't compile, it's just to put all definitions
in the same place to better explain what I mean.

--------8<--------------------------
typedef void* gpointer;
typedef void  (*GFunc)          (gpointer data,
                                 gpointer user_data);
typedef void  (*GDestroyNotify) (gpointer       data);

void
g_queue_free_full (GQueue         *queue,
                   GDestroyNotify  free_func)
{
  g_queue_foreach (queue, (GFunc) free_func, NULL);
  g_queue_free (queue);
}

void
g_queue_foreach (GQueue   *queue,
                 GFunc     func,
                 gpointer  user_data)
{
  GList *list;

  g_return_if_fail (queue != NULL);
  g_return_if_fail (func != NULL);

  list = queue->head;
  while (list)
    {
      GList *next = list->next;
      func (list->data, user_data);
      list = next;
    }
}
--------8<--------------------------

Again for the record, the function g_queue_free_full
was added with this commit
http://git.gnome.org/browse/glib/commit/?id=1d4009e6f7e1d368b3e3df2fa41b007277b600d8
between tags 2.31.4 and 2.31.6; as the patch description states,
it is a convenience method and fixes the bug
https://bugzilla.gnome.org/show_bug.cgi?id=657433

Best regards
Giovanni Gherdovich
_______________________________________________
gtk-devel-list mailing list
gtk-devel-list gnome org
https://mail.gnome.org/mailman/listinfo/gtk-devel-list


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]