2011-01-30 19 views
5

Możliwe, że jest za późno, ale uważam za co najmniej ciekawy, że kilka linii wydaje się powodować usterkę segmentacji tylko wtedy, gdy skompilowano ją z optymalizacją gcc, nawet "-O1"!Błąd segmentacji po włączeniu optymalizacji w prostej aplikacji GTK +?

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); 

To backtrace:

(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 jest dokładnie pierwsza linia wymienione powyżej, wydaje się "gtk_dialog_new_with_buttons" jest winowajcą ...

wersje:
gcc: 4.4.3
GTK +: 2.20.1

BTW, zapomniałem wspomnieć, że CO Wykasowanie niektórych linii po konfliktowe wezwanie zapobiega temu. Zwłaszcza wiersz z "gtk_container_add (GTK_CONTAINER (hb), cb);"

Próbowałem prawie wszystkie odpowiednie kombinacje GtkTypes/GTK_MACROS, to nie ma znaczenia.

+0

Czy otrzymujesz ostrzeżenia podczas kompilacji? – dreamlax

+1

Bez ostrzeżeń, oczywiście! :-) Z "gcc -c" 'pkg-config --cflags gtk + -2.0'' -std = c99 -Wall -O1 -ggdb" -> – gatopeich

+1

Tymczasem znalazłem, że dodanie dodatkowego 0 do zmiennej argument lista gtk_dialog_new_with_buttons() wydaje się rozwiązywać problem, nawet jeśli nie odpowiada jego dokumentacji. Odpowiem sam, jeśli nie otrzymamy bardziej wiarygodnego wyjaśnienia na temat va_args, optymalizacji i/lub tego konkretnego problemu :-P. – gatopeich

Odpowiedz

3

Krótko mówiąc: użyj NULL gdy instrukcja mówi NULL, a nie zwykły !

(Ponieważ nie mogę wybrać komentarze jako odpowiedź, piszę odpowiedzieć sobie, dając kredyt pomocnych uwag ...)

GTK + dokumentacja stany to:

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 

Ale byłem leniwy, że noc i wpisane tylko „0”, gdzie oczekiwano NULL:

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

... Nie zauważając, że NULL jest punktem er, który w moim 64-bitowym systemie ma szerokość 64 bitów, podczas gdy 0 to 32-bitowa liczba całkowita ...

Wygląda na to, że na liście argumentów zmiennych kompilator nie był w stanie wykryć niespójności: kod kompilowany cicho za pomocą -Wall.

Zgodnie z sugestią Myforwik, która została dodatkowo wyjaśniona, użycie "NULL" zamiast "0" rozwiązało problem. Dzięki chłopaki!

Dla porównania wykonałem test kompilujący w trybie 32-bitowym, gdzie NULL ma również 32-bity, w tym przypadku nie wystąpił błąd segfault. Nadal jest niepoprawny, ponieważ dokumentacja jest wystarczająco przejrzysta, a NULL nie wynosi 0, bez względu na to, co kiedykolwiek powiedzą komisarze C++! ;-)

+3

Kluczem * getcha * tutaj jest lista argumentów zmiennych - kompilator języka C przekształci literalne '0' w wskaźnik' NULL' **, gdy wie ** potrzebujesz wskaźnika - i nie może (koniecznie) wiedz, że podczas kompilacji wywołania varargs! – detly