Deferencing type-punned pointers, and how to stop gcc giving you a warning
- From: Chris Sherlock <csherlock optusnet com au>
- To: desktop-devel-list gnome org
- Subject: Deferencing type-punned pointers, and how to stop gcc giving you a warning
- Date: Sun, 25 Apr 2004 19:04:34 +1000
Hi all,
I've been looking at a few warnings that gcc have been spitting out at
me lately about "Derefencing type-punned pointer will break
strict-aliasing rules".
Here's what the gcc manual has to say about it:
> -fstrict-aliasing Allows the compiler to assume the strictest
> aliasing rules applicable to the language being compiled. For C (and
> C++), this activates optimizations based on the type of expressions.
> In particular, an object of one type is assumed never to reside at
> the same address as an object of a different type, unless the types
> are almost the same. For example, an "unsigned int" can alias an
> "int", but not a "void*" or a "double". A character type may alias
> any other type.
>
> Pay special attention to code like this:
>
> union a_union { int i; double d; };
>
> int f() { a_union t; t.d = 3.0; return t.i; }
>
> The practice of reading from a different union member than the one
> most recently written to (called ‘‘type-punning’’) is common. Even
> with -fstrict-aliasing, type-punning is allowed, provided the memory
> is accessed through the union type. So, the code above will work as
> expected. However, this code might not:
>
> int f() { a_union t; int* ip; t.d = 3.0; ip = &t.i; return *ip; }
>
> Every language that wishes to perform language-specific alias
> analysis should define a function that computes, given an "tree"
> node, an alias set for the node. Nodes in different alias sets are
> not allowed to alias. For an example, see the C front-end function
> "c_get_alias_set".
>
> Enabled at levels -O2, -O3, -Os."
>
and
> -Wstrict-aliasing This option is only active when -fstrict-aliasing
> is active. It warns about code which might break the strict aliasing
> rules that the compiler is using for optimization. The warning does
> not catch all cases, but does attempt to catch the more common
> pitfalls. It is included in -Wall.
When I compiled gtk+2.4 (and gtk+2.2) I found that I was getting quite a
few of these warnings. During my discovery of the problem - see
http://bugzilla.gnome.org/show_bug.cgi?id=140722 - I've found some
general rules to try to prevent these warnings:
* if you use g_module_symbol, and you need to use a void* function
pointer with multiple parameters to get the module's symbol pointer,
then *also* declare a gpointer pfunc_name, and declare the function
pointer itself to be "void (*func_name) (int x, int y)=NULL;" Then, call
g_module_symbol and pass the third parameter as &pfunc_name. As soon as
it's been called, then assign func_name the address of pfunc_name.
Example (from gdk-pixbuf/queryloaders.c):
static void
query_module (const char *dir, const char *file)
{
char *path;
GModule *module;
// needed or gcc will give a warning that dereferencing
// type-punned pointer will break strict-aliasing rules
gpointer pfill_info;
gpointer pfill_vtable;
void (*fill_info) (GdkPixbufFormat *info)=NULL;
void (*fill_vtable) (GdkPixbufModule *module)=NULL;
if (g_path_is_absolute (file))
path = g_strdup (file);
else
path = g_build_filename (dir, file, NULL);
module = g_module_open (path, 0);
if (module &&
g_module_symbol (module, "fill_info", &pfill_info) &&
g_module_symbol (module, "fill_vtable", &pfill_vtable)) {
GdkPixbufFormat *info;
GdkPixbufModule *vtable;
fill_info = pfill_info;
fill_vtable = pfill_vtable;
.
.
.
etc
As far as I can tell, gcc doesn't like casting a function pointer with a
specific parameter signature to a regular gpointer. So you have to pass
an actual gpointer variable's address to g_module_symbol and then copy
over the the gpointer variable's address to the actual function pointer
and THEN call the function pointer.
* if you use gdk_window_get_user_data, parameter 2 of this function is a
gpointer*, so again you can't just do something like:
> GtkWidget *widget;
> GdkWindow *window;
>
> gdk_window_get_user_data(window, (gpointer*)&widget);
This is because a gpointer * is really void **, and GtkWidget is a
typedef to the structure _GtkWidget. As types, these are obviously
incompatible, however as pointers they're the "same" type (ie and
address to an area of memory)... however gcc it breaks gcc's
strict-aliasing rules. You can't cast a struct pointer to a gpointer*
without the warning (though your program will compile OK), but you can
cast a gpointer* to a GtkWidget*. Therefore, you need to do the following:
> GtkWidget *widget;
> GdkWindow *window;
>
> gpointer pwidget;
>
> gdk_window_get_user_data(window, &pwidget);
> widget = (GtkWidget*) &pwidget;
Obviously, these examples can be applied to other areas where you get
this warning.
Anyway, I hope this helps somewhat.
Chris
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]