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

In order to support varargs ('...', 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.

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.

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

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

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;

Again for the record, the function g_queue_free_full
was added with this commit
between tags 2.31.4 and 2.31.6; as the patch description states,
it is a convenience method and fixes the bug

Best regards
Giovanni Gherdovich
gtk-devel-list mailing list
gtk-devel-list gnome org

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