分段错误 GTK+ 应用程序

Segmentation Fault GTK+ application

我正在使用 Glade 制作 GTK 3+ 应用程序。 这是我在 C 中的结构:

# include       <gtk/gtk.h>                                                                                                                                                       
# include       <stdio.h>                                                                                                                                                         
# include       <stdlib.h>                                                                                                                                                        

typedef struct  s_gtk                                                                                                                                                             
{                                                                                                                                                                                 
  GtkBuilder    *interface;                                                                                                                                                       
  GtkWidget     *MainWindow;                                                                                                                                                      
  GtkWidget     *AddObject;                                                                                                                                                       
  GtkWidget     *DeleteObject;                                                                                                                                                    
  GtkWidget     *Launch;                                                                                                                                                          
  GError        *error;                                                                                                                                                           
  gchar         *filename;                                                                                                                                                        
}               t_gtk;

我初始化 gtk->AddObject 的函数,它在主函数中被调用:

    if ((gtk->interface = gtk_builder_new()) == NULL ||                                                                                                                             
      (gtk->filename = g_build_filename("interface.glade", NULL)) == NULL)                                                                                                        
    {                                                                                                                                                                             
      g_error("%s", gtk->error->message);                                                                                                                                         
      g_error_free(gtk->error);                                                                                                                                                   
      return (gtk->error->code);                                                                                                                                                  
    }                                                                                                                                                                             
  gtk_builder_add_from_file(gtk->interface, gtk->filename, &gtk->error);                                                                                                          
  g_free(gtk->filename);                                                                                                                                                          
  if (gtk->error)                                                                                                                                                                 
    {                                                                                                                                                                             
      g_printerr("%s\n", gtk->error->message);                                                                                                                                    
      g_error_free(gtk->error);                                                                                                                                                   
      return (gtk->error->code);                                                                                                                                                  
    }                                                                                                                                                                             
  gtk->MainWindow = GTK_WIDGET(gtk_builder_get_object                                                                                                                             
                              (gtk->interface, "MainWindow"));                                                                                                                    
  gtk->AddObject = GTK_WIDGET(gtk_builder_get_object                                                                                                                              
                             (gtk->interface, "AddDialog"));                                                                                                                      
  gtk_builder_connect_signals(gtk->interface, gtk);                                                                                                                               
  return (0);

我的 AddObject 处理程序:

void            on_AddObject_clicked(gpointer user_data)                                                                                                                          
{                                                                                                                                                                                 
  t_gtk         *gtk;                                                                                                                                                             
  gint          response;                                                                                                                                                         

  gtk = (t_gtk *)user_data;                                                                                                                                                       
  printf("I'm here\n");                                                                                                                                                           
  response = gtk_dialog_run(GTK_DIALOG(gtk->AddObject));                                                                                                                          
  printf("I'm here2\n");                                                                                                                                                          
  if (response == 1)                                                                                                                                                              
    {                                                                                                                                                                             
      printf("Add pressed!\n");                                                                                                                                                   
    }                                                                                                                                                                             
  else                                                                                                                                                                            
    {                                                                                                                                                                             
      printf("Cancel pressed!\n");                                                                                                                                                
    }                                                                                                                                                                             
  gtk_widget_hide(gtk->AddObject);                                                                                                                                                
}

我在这里遇到段错误,但我不知道为什么...:[=​​20=]

response = gtk_dialog_run(GTK_DIALOG(gtk->AddObject));    

Valgrind 说:

Invalid read of size 8
==7272==    at 0x6B16620: g_type_check_instance_cast (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.4200.1)
==7272==    by 0x401063: on_AddObject_clicked (in /home/vives_j/Documents/Epitech/Tests/main)
==7272==    by 0x6AF3473: ??? (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.4200.1)
==7272==    by 0x6B0D086: g_signal_emit_valist (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.4200.1)
==7272==    by 0x6B0D9DE: g_signal_emit (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.4200.1)
==7272==    by 0x4F3CA1C: ??? (in /usr/lib/x86_64-linux-gnu/libgtk-3.so.0.1400.5)
==7272==    by 0x4F3CA74: ??? (in /usr/lib/x86_64-linux-gnu/libgtk-3.so.0.1400.5)
==7272==    by 0x6AF3473: ??? (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.4200.1)
==7272==    by 0x6B0D086: g_signal_emit_valist (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.4200.1)
==7272==    by 0x6B0D9DE: g_signal_emit (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.4200.1)
==7272==    by 0x4F3A9FF: ??? (in /usr/lib/x86_64-linux-gnu/libgtk-3.so.0.1400.5)
==7272==    by 0xB795DBF: ffi_call_unix64 (in /usr/lib/x86_64-linux-gnu/libffi.so.6.0.2)
==7272==  Address 0x400000003 is not stack'd, malloc'd or (recently) free'd
==7272== 
==7272== 
==7272== Process terminating with default action of signal 11 (SIGSEGV)
==7272==  Access not within mapped region at address 0x400000003
==7272==    at 0x6B16620: g_type_check_instance_cast (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.4200.1)
==7272==    by 0x401063: on_AddObject_clicked (in /home/vives_j/Documents/Epitech/Tests/main)
==7272==    by 0x6AF3473: ??? (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.4200.1)
==7272==    by 0x6B0D086: g_signal_emit_valist (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.4200.1)
==7272==    by 0x6B0D9DE: g_signal_emit (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.4200.1)
==7272==    by 0x4F3CA1C: ??? (in /usr/lib/x86_64-linux-gnu/libgtk-3.so.0.1400.5)
==7272==    by 0x4F3CA74: ??? (in /usr/lib/x86_64-linux-gnu/libgtk-3.so.0.1400.5)
==7272==    by 0x6AF3473: ??? (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.4200.1)
==7272==    by 0x6B0D086: g_signal_emit_valist (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.4200.1)
==7272==    by 0x6B0D9DE: g_signal_emit (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.4200.1)
==7272==    by 0x4F3A9FF: ??? (in /usr/lib/x86_64-linux-gnu/libgtk-3.so.0.1400.5)
==7272==    by 0xB795DBF: ffi_call_unix64 (in /usr/lib/x86_64-linux-gnu/libffi.so.6.0.2)
==7272==  If you believe this happened as a result of a stack
==7272==  overflow in your program's main thread (unlikely but
==7272==  possible), you can try to increase the size of the
==7272==  main thread stack using the --main-stacksize= flag.
==7272==  The main thread stack size used in this run was 8388608.

我编译为(来自 make 命令):

gcc -Wextra -Wall -ansi -pedantic -I. -O3 -D REENTRANT -rdynamic -DGTK_DISABLE_DEPRECATED=1 -DGDK_DISABLE_DEPRECATED -DGDK_PIXBUF_DISABLE_DEPRECATED -DG_DISABLE_DEPRECATED -DGTK_MULTIHEAD_SAFE=1 -DGTK_MULTIDEVICE_SAFE=1 `pkg-config gmodule-export-2.0 --libs` `pkg-config gtk+-3.0 --cflags`   -c -o main.o main.c
gcc main.o -o main `pkg-config gtk+-3.0 --libs` `pkg-config gmodule-export-2.0 --libs`

GDB 结果:

GNU gdb (Debian 7.7.1+dfsg-5) 7.7.1
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./main...done.
(gdb) 
(gdb) run
Starting program: /home/vives_j/Documents/Epitech/Tests/main 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

(process:3752): Gtk-WARNING **: Locale not supported by C library.
    Using the fallback 'C' locale.
[New Thread 0x7fffee33c700 (LWP 3756)]
[New Thread 0x7fffedb3b700 (LWP 3757)]
[New Thread 0x7fffecfe7700 (LWP 3759)]
I'm here

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff5f0f620 in g_type_check_instance_cast ()
   from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
(gdb) backtrac
#0  0x00007ffff5f0f620 in g_type_check_instance_cast ()
   from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#1  0x0000000000401034 in on_AddObject_clicked (user_data=0x8d0350)
    at main.c:57
#2  0x00007ffff5eec474 in ?? ()
   from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#3  0x00007ffff5f06087 in g_signal_emit_valist ()
   from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#4  0x00007ffff5f069df in g_signal_emit ()
   from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#5  0x00007ffff762ca1d in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#6  0x00007ffff762ca75 in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#7  0x00007ffff5eec474 in ?? ()
   from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#8  0x00007ffff5f06087 in g_signal_emit_valist ()
   from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#9  0x00007ffff5f069df in g_signal_emit ()
   from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#10 0x00007ffff762aa00 in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#11 0x00007ffff127edc0 in ffi_call_unix64 ()
   from /usr/lib/x86_64-linux-gnu/libffi.so.6
#12 0x00007ffff127e828 in ffi_call ()
   from /usr/lib/x86_64-linux-gnu/libffi.so.6
---Type <return> to continue, or q <return> to quit---
#13 0x00007ffff5eecebc in g_cclosure_marshal_generic_va ()
   from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#14 0x00007ffff5eec474 in ?? ()
   from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#15 0x00007ffff5f06087 in g_signal_emit_valist ()
   from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#16 0x00007ffff5f069df in g_signal_emit ()
   from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#17 0x00007ffff76cf191 in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#18 0x00007ffff5eef233 in g_cclosure_marshal_VOID__BOXEDv ()
   from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#19 0x00007ffff5eec474 in ?? ()
   from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#20 0x00007ffff5f06087 in g_signal_emit_valist ()
   from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#21 0x00007ffff5f069df in g_signal_emit ()
   from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#22 0x00007ffff76cc94e in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#23 0x00007ffff76cdd9b in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#24 0x00007ffff76d05e0 in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#25 0x00007ffff76a3e7b in gtk_event_controller_handle_event ()
   from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#26 0x00007ffff783f41d in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
---Type <return> to continue, or q <return> to quit---
#27 0x00007ffff771241e in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#28 0x00007ffff5eec474 in ?? ()
   from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#29 0x00007ffff5f05b30 in g_signal_emit_valist ()
   from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#30 0x00007ffff5f069df in g_signal_emit ()
   from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#31 0x00007ffff7842de4 in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#32 0x00007ffff770fd2e in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#33 0x00007ffff771193e in gtk_main_do_event ()
   from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#34 0x00007ffff72b8b12 in ?? () from /usr/lib/x86_64-linux-gnu/libgdk-3.so.0
#35 0x00007ffff5c16c5d in g_main_context_dispatch ()
   from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#36 0x00007ffff5c16f48 in ?? () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#37 0x00007ffff5c17272 in g_main_loop_run ()
   from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#38 0x00007ffff7710bf5 in gtk_main ()
   from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#39 0x0000000000401275 in main (ac=1, av=0x7fffffffdcf8) at main.c:115
(gdb) quit

第 57 行是我之前发布的导致崩溃的行。

空地文件: http://pastebin.com/JrHza6iW 我想我有线索了。因为,当我从教程中获取此示例代码时: http://pastebin.com/WpJ6kWQB 并使用(及其构建器文件)编译它:

gcc -o dialog1 dialog1.c $(pkg-config --cflags --libs gtk+-2.0 \
 *        gmodule-export-2.0)

它可以工作,但是如果我将 gtk+-2.0 更改为 3.0,它会在同样的地方崩溃。 提前谢谢你!!

Valgrind 在这里对你帮助不大。删除.oexecutable,重新编译,在编译命令中加入-g-O0

然后运行gdb,并且,当段错误发生时,做一个backtrace。您应该能够按照它找到问题所在。 (post 这里的回溯)

您在 运行 期间看到任何消息了吗?甚至警告?

我发现了问题。 在我的处理函数中,我们需要将我们点击的小部件的类型传入参数。在这里,它是一个 GtkButton,所以我将它添加到我收到的参数中:

void            on_AddObject_clicked(GtkButton *button, gpointer user_data)                                                                                                                          
{                                                                                                                                                                                 
  t_gtk         *gtk;                                                                                                                                                             
  gint          response;                                                                                                                                                         

  gtk = (t_gtk *)user_data;  
  (void) button;                                                                                                                                           
  printf("I'm here\n");                                                                                                                                                           
  response = gtk_dialog_run(GTK_DIALOG(gtk->AddObject));                                                                                                                          
  printf("I'm here2\n");                                                                                                                                                          
  if (response == 1)                                                                                                                                                              
    {                                                                                                                                                                             
      printf("Add pressed!\n");                                                                                                                                                   
    }                                                                                                                                                                             
  else                                                                                                                                                                            
    {                                                                                                                                                                             
      printf("Cancel pressed!\n");                                                                                                                                                
    }                                                                                                                                                                             
  gtk_widget_hide(gtk->AddObject);                                                                                                                                                
}

我认为 GTK 在后台需要它。所以解决了。 无论如何,谢谢你的帮助! :)