2011-01-30 8 views
5

Puede ser que sea demasiado tarde, pero me parece al menos curioso que las siguientes líneas parecen estar causando un error de segmentación si y solo cuando se compila con la optimización de gcc, ¡incluso "-O1"!¿Error de segmentación al habilitar la optimización en una aplicación GTK + simple?

settings_dialog = gtk_dialog_new_with_buttons("gatotray Settings" 
    , NULL, 0, GTK_STOCK_CANCEL, FALSE, GTK_STOCK_SAVE, TRUE, 0); 
g_signal_connect(G_OBJECT(settings_dialog), "response", G_CALLBACK(gtk_widget_destroy), NULL); 
g_signal_connect(G_OBJECT(settings_dialog), "destroy", G_CALLBACK(settings_destroyed), NULL); 
GtkWidget *vb = gtk_dialog_get_content_area(GTK_DIALOG(settings_dialog)); 
GtkWidget *hb = gtk_hbox_new(FALSE, 3); 
gtk_container_add(GTK_CONTAINER(hb), gtk_label_new("Background:")); 
GtkWidget *cb = gtk_color_button_new(); 
gtk_container_add(GTK_CONTAINER(hb), cb); 
gtk_container_add(GTK_CONTAINER(vb), hb); 

Este es el trazado inverso:

(gdb) backtrace 
#0 0x00007ffff4d88052 in ??() from /lib/libc.so.6 
#1 0x00007ffff5304112 in g_strdup() from /lib/libglib-2.0.so.0 
#2 0x00007ffff5bc799d in ??() from /usr/lib/libgobject-2.0.so.0 
#3 0x00007ffff5ba826c in g_object_new_valist() 
    from /usr/lib/libgobject-2.0.so.0 
#4 0x00007ffff5ba84f1 in g_object_new() from /usr/lib/libgobject-2.0.so.0 
#5 0x00007ffff78502d5 in gtk_button_new_from_stock() 
    from /usr/lib/libgtk-x11-2.0.so.0 
#6 0x00007ffff787cc95 in gtk_dialog_add_button() 
    from /usr/lib/libgtk-x11-2.0.so.0 
#7 0x00007ffff787cd60 in ??() from /usr/lib/libgtk-x11-2.0.so.0 
#8 0x00007ffff787cf60 in gtk_dialog_new_with_buttons() 
    from /usr/lib/libgtk-x11-2.0.so.0 
#9 0x0000000000402bb9 in show_settings_dialog() at settings.c:24 
#10 0x0000000000403328 in main (argc=1, argv=0x7fffffffe2b8) at gatotray.c:286 

... settings.c: 24 es exactamente la primera línea mencionados anteriormente, parece que "gtk_dialog_new_with_buttons" es el culpable ...

versiones:
gcc: 4.4.3
GTK +: 2.20.1

Por cierto, se me olvidó mencionar que la co Según ciertas líneas después de, la llamada conflictiva impide que ocurra. Particularmente la línea con "gtk_container_add (GTK_CONTAINER (hb), cb);"

Probé casi todas las combinaciones adecuadas de GtkTypes/GTK_MACROS, no hace la diferencia.

+0

¿Recibes alguna advertencia cuando compilas? – dreamlax

+1

¡Sin advertencias, por supuesto! :-) Con "gcc -c' 'pkg-config --cflags gtk + -2.0'' -std = c99 -Wall -O1 -ggdb" -> – gatopeich

+1

Mientras tanto, encontré que agregando un 0 extra al argumento variable La lista de gtk_dialog_new_with_buttons() parece resolver el problema, incluso cuando no se corresponde con su documentación. Yo mismo lo responderé si no obtenemos una explicación más autorizada sobre va_args, la optimización y/o este problema específico :-P. – gatopeich

Respuesta

3

Para resumir: utilizar NULL cuando el manual dice NULL, y no una llanura !

(Ya que no puedo elegir los comentarios como una respuesta, estoy escribiendo la respuesta a mí mismo, dando crédito a los comentarios útiles ...)

GTK + documentación indica esto:

GtkWidget* 
gtk_dialog_new_with_buttons (const gchar *title, 
          GtkWindow  *parent, 
          GtkDialogFlags flags, 
          const gchar *first_button_text, 
         ...); 

title : Title of the dialog, or NULL. allow-none. 
parent : Transient parent of the dialog, or NULL. allow-none. 
flags : from GtkDialogFlags 
first_button_text : stock ID or text to go in first button, or NULL. allow-none. 
... : response ID for first button, then additional buttons, ending with NULL 

Pero yo era perezoso esa noche y escribió sólo un '0', donde se esperaba que el NULL:

settings_dialog = GTK_DIALOG(gtk_dialog_new_with_buttons("gatotray Settings" 
    , NULL, 0, GTK_STOCK_CANCEL, FALSE, GTK_STOCK_SAVE, TRUE, 0)); 

... Sin darse cuenta de que NULL es un punto er que en mi sistema de 64 bits tiene 64 bits de ancho, mientras que 0 es un entero de 32 bits ...

Además, parece que en la lista de argumentos variables el compilador no pudo detectar la incoherencia: el código compilado en silencio con -Wall.

Como se sugirió Myforwik y Havoc P, usando 'NULL' en lugar de '0' solucionado el problema. ¡Gracias chicos!

Para el registro, hice una prueba de compilación en modo de 32 bits donde NULL también es de 32 bits, y en ese caso no hubo segfault. Sin embargo, sigue siendo incorrecto, ya que la documentación es lo suficientemente clara, y NULL no es 0, ¡sin importar lo que digan los miembros del comité de C++! ;-)

+3

La clave * gotcha * aquí es la lista de argumentos variables - un compilador de C transformará cualquier literal '0' en un puntero' NULL' ** cuando sabe ** necesita un puntero - y no puede (necesariamente) saber que al compilar una invocación varargs! – detly

Cuestiones relacionadas