GTK C segv:添加新信号会导致segv

时间:2017-12-20 14:42:05

标签: c pointers gtk3 sigsegv

我在现有测试gui中引入新的开关信号时遇到了sigsegv错误。

UI有3个可能的事件源,两个事件框和一个开关。单击事件框时,它们的行为正常,但是如果切换开关,则单击其中一个事件框会导致segv(行为1)。

此外,如果从new运行,首先切换开关然后单击事件框也会导致segv(行为2)。两者的segv总是出现在同一个地方(如果使用其中一个事件框作为例子),如下所示:

if (((interface *) toggle)->eth0->ip_enabled) {

我在代码方面可以提出的最简单的表现如下(借口包括):

/*
 * STRIPPED DOWN VERSION
 */
#include <arpa/inet.h>
#include <gtk/gtk.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>


#define IPV4_ENABLED                1
#define IPV4_DISABLED               0
#define SELECTED                    1

typedef struct {
    int ip_enabled;
} net;

typedef struct {
    net *eth0;
    net *wlan0;
    int type;
} interface;

typedef enum {
    IT_ETH0,
    IT_WLAN0,
    IT_UNASSIGNED = 999,
} interface_type;

typedef struct {
    int active;
    interface *port;
    int debug;
} test_parameters;

void wired (net *eth0);

void wifi (net *wlan0);

int main (int argc, char *argv[]) {

    GtkBuilder *builder;
    GtkWidget *window;
    GError *gtk_error = NULL;

    net *eth0 = g_slice_new (net);
    net *wlan0 = g_slice_new (net);
    interface *toggle = g_slice_new (interface);

    test_parameters *test = g_slice_new (test_parameters);

    test->port->type == IT_UNASSIGNED;

        /*Add interfaces to struct "interface" */
    toggle->eth0 = eth0;
    toggle->wlan0 = wlan0;

    toggle->eth0->ip_enabled = 0;
    toggle->wlan0->ip_enabled = 0;

    if (NULL == toggle->eth0)
        fprintf (stdout, "%s\n", "eth0 is null ");

    if (NULL == toggle->wlan0)
        fprintf (stdout, "%s\n", "wlan0 is null ");


    gtk_init (&argc, &argv);

    builder = gtk_builder_new ();
    if (!gtk_builder_add_from_file (builder, "glade/window_main.glade", NULL)) {
        fprintf (stdout, "%s%s\n", "Error loading file with the reason: ", gtk_error->message);
        g_free (gtk_error);
        exit (EXIT_FAILURE);
    }

    window = GTK_WIDGET (gtk_builder_get_object (builder, "window_main"));

    gtk_builder_connect_signals (builder, toggle);
    gtk_builder_connect_signals (builder, test);

    g_object_unref (builder);

    wired (eth0);
    wifi (wlan0);
    gtk_widget_show (window);

    gtk_main ();

    g_slice_free (net, eth0);
    g_slice_free (net, wlan0);
    g_slice_free (interface, toggle);

    return 0;

}

void wifi (net *wlan0) {

    if (1) {
        wlan0->ip_enabled = IPV4_ENABLED;
    }

}

void wired (net *eth0) {

    if (1) {
        eth0->ip_enabled = IPV4_ENABLED;
    }

}

G_MODULE_EXPORT gboolean on_eventbox_image_wired_button_press_event (GtkWidget *widget,
    GdkEvent *event, gpointer toggle) {

    if (((interface *) toggle)->eth0 == NULL) {
        printf("%s\n", "WIRED: eth0 IS NULL - REMOVE ME");
    }

    if (((interface *) toggle) == NULL) {
        printf("%s\n", "WIRED: toggle IS NULL - REMOVE ME");
    }

    if (((interface *) toggle)->eth0->ip_enabled) {
        printf("%s\n", "WIRED: eth0 is ip enabled - REMOVE ME");
        ((interface *) toggle)->type = IT_ETH0;
        if (((interface *) toggle)->wlan0->ip_enabled) {
            printf("%s\n", "WIRED: wlan0 is ip enabled, adjust - REMOVE ME");
        }

    }
    return 0;
}

G_MODULE_EXPORT gboolean on_eventbox_image_wifi_button_press_event (GtkWidget *widget,
    GdkEvent *event, gpointer toggle) {

    /* Check to see if we have IP address so we can change the colour otherwise leave it red */
    if (((interface *) toggle)->wlan0->ip_enabled) {
        printf("%s\n", "WLAN has IP enabled");
        ((interface *) toggle)->type = IT_ETH0;
        if (((interface *) toggle)->eth0->ip_enabled) {
            printf("%s\n", "WLAN: eth0 is ip enabled, adjust - REMOVE ME");
        }

    }

    return 0;       
}

G_MODULE_EXPORT gboolean on_switch_test_on_state_set (GtkSwitch *widget,
    gboolean state, gpointer test) {

    (((test_parameters *) test)->active) = state;

    fprintf (stdout, "%s%i\n", "Signal fired and the state is ", state);

    return 0;

}

void on_window_main_destroy () {

    gtk_main_quit ();
}

gdb bt是:

(gdb) run
Starting program: /home/j2/simplified_example/simplified_example 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7fffed0c4700 (LWP 6979)]
[New Thread 0x7fffec8c3700 (LWP 6980)]
WIRED: eth0 is ip enabled - REMOVE ME
WIRED: wlan0 is ip enabled, adjust - REMOVE ME
Signal fired and the state is 1

Thread 1 "simplified_exam" received signal SIGSEGV, Segmentation fault.
0x0000000000401110 in on_eventbox_image_wired_button_press_event (widget=0x6a7260 [GtkEventBox], event=0x994cb0, toggle=0x624800)
    at src/simplified_example1.c:134
134     if (((interface *) toggle)->eth0->ip_enabled) {
(gdb) bt
#0  0x0000000000401110 in on_eventbox_image_wired_button_press_event (widget=0x6a7260 [GtkEventBox], event=0x994cb0, toggle=0x624800)
    at src/simplified_example1.c:134
#5  0x00007ffff728008f in <emit signal ??? on instance 0x6a7260 [GtkEventBox]> (instance=instance@entry=0x6a7260, signal_id=<optimised out>, detail=detail@entry=0) at /build/glib2.0-prJhLS/glib2.0-2.48.2/./gobject/gsignal.c:3441
    #1  0x00007ffff76bafac in _gtk_marshal_BOOLEAN__BOXED (closure=0x6ffe50, return_value=0x7fffffffd940, n_param_values=<optimised out>, param_values=0x7fffffffd9a0, invocation_hint=<optimised out>, marshal_data=<optimised out>) at /build/gtk+3.0-2Ut_nl/gtk+3.0-3.18.9/./gtk/gtkmarshalers.c:86
    #2  0x00007ffff7264fa5 in g_closure_invoke (closure=0x6ffe50, return_value=return_value@entry=0x7fffffffd940, n_param_values=2, param_values=param_values@entry=0x7fffffffd9a0, invocation_hint=invocation_hint@entry=0x7fffffffd920) at /build/glib2.0-prJhLS/glib2.0-2.48.2/./gobject/gclosure.c:804
    #3  0x00007ffff7276fc1 in signal_emit_unlocked_R (node=node@entry=0x653b40, detail=detail@entry=0, instance=instance@entry=0x6a7260, emission_return=emission_return@entry=0x7fffffffdab0, instance_and_params=instance_and_params@entry=0x7fffffffd9a0)
    at /build/glib2.0-prJhLS/glib2.0-2.48.2/./gobject/gsignal.c:3629
    #4  0x00007ffff727f7f9 in g_signal_emit_valist (instance=<optimised out>, signal_id=<optimised out>, detail=<optimised out>, var_args=var_args@entry=0x7fffffffdb60) at /build/glib2.0-prJhLS/glib2.0-2.48.2/./gobject/gsignal.c:3395
#6  0x00007ffff77f8c3c in gtk_widget_event_internal (widget=0x6a7260 [GtkEventBox], event=0x994cb0)
    at /build/gtk+3.0-2Ut_nl/gtk+3.0-3.18.9/./gtk/gtkwidget.c:7692
#7  0x00007ffff76b83be in propagate_event (topmost=<optimised out>, event=<optimised out>, widget=0x6a7260 [GtkEventBox])
    at /build/gtk+3.0-2Ut_nl/gtk+3.0-3.18.9/./gtk/gtkmain.c:2527
#8  0x00007ffff76b83be in propagate_event (widget=<optimised out>, event=0x994cb0, captured=<optimised out>, topmost=0x0)
    at /build/gtk+3.0-2Ut_nl/gtk+3.0-3.18.9/./gtk/gtkmain.c:2629
#9  0x00007ffff76ba1bc in gtk_main_do_event (event=0x994cb0) at /build/gtk+3.0-2Ut_nl/gtk+3.0-3.18.9/./gtk/gtkmain.c:1850
#10 0x00007ffff66dcd92 in gdk_event_source_dispatch (source=<optimised out>, callback=<optimised out>, user_data=<optimised out>)
    at /build/gtk+3.0-2Ut_nl/gtk+3.0-3.18.9/./gdk/x11/gdkeventsource.c:369
#11 0x00007ffff6f8e197 in g_main_context_dispatch (context=0x640980) at /build/glib2.0-prJhLS/glib2.0-2.48.2/./glib/gmain.c:3154
---Type <return> to continue, or q <return> to quit---
#12 0x00007ffff6f8e197 in g_main_context_dispatch (context=context@entry=0x640980) at /build/glib2.0-prJhLS/glib2.0-2.48.2/./glib/gmain.c:3769
#13 0x00007ffff6f8e3f0 in g_main_context_iterate (context=0x640980, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimised out>)
    at /build/glib2.0-prJhLS/glib2.0-2.48.2/./glib/gmain.c:3840
#14 0x00007ffff6f8e712 in g_main_loop_run (loop=0x8d14b0) at /build/glib2.0-prJhLS/glib2.0-2.48.2/./glib/gmain.c:4034
#15 0x00007ffff76b9395 in gtk_main () at /build/gtk+3.0-2Ut_nl/gtk+3.0-3.18.9/./gtk/gtkmain.c:1241
#16 0x0000000000401065 in main (argc=1, argv=0x7fffffffdfd8) at src/simplified_example1.c:97
(gdb) 
(gdb) 
(gdb) 

请提前感谢您提供任何帮助。

编辑:根据要求添加了glade文件 - 为了测试目的,它被简化:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.18.3 -->
<interface>
  <requires lib="gtk+" version="3.12"/>
  <object class="GtkWindow" id="window_main">
    <property name="can_focus">False</property>
    <property name="title" translatable="yes">Main Window</property>
    <property name="default_width">640</property>
    <property name="default_height">480</property>
    <property name="decorated">False</property>
    <signal name="destroy" handler="on_window_main_destroy" swapped="no"/>
    <child>
      <object class="GtkFixed" id="fixed_background">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <child>
          <object class="GtkImage" id="image_background">
            <property name="name">4</property>
            <property name="width_request">640</property>
            <property name="height_request">480</property>
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="stock">gtk-missing-image</property>
          </object>
        </child>
        <child>
          <object class="GtkEventBox" id="eventbox_image_wired">
            <property name="width_request">100</property>
            <property name="height_request">80</property>
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="visible_window">False</property>
            <property name="above_child">True</property>
            <signal name="button-press-event" handler="on_eventbox_image_wired_button_press_event" swapped="no"/>
            <child>
              <object class="GtkImage" id="image_wired">
                <property name="width_request">100</property>
                <property name="height_request">80</property>
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="xalign">0</property>
                <property name="yalign">0</property>
                <property name="icon_name">applications-graphics</property>
              </object>
            </child>
          </object>
          <packing>
            <property name="x">35</property>
            <property name="y">20</property>
          </packing>
        </child>
        <child>
          <object class="GtkEventBox" id="eventbox_image_wifi">
            <property name="width_request">100</property>
            <property name="height_request">80</property>
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="visible_window">False</property>
            <property name="above_child">True</property>
            <signal name="button-press-event" handler="on_eventbox_image_wifi_button_press_event" swapped="no"/>
            <child>
              <object class="GtkImage" id="image_wifi">
                <property name="width_request">101</property>
                <property name="height_request">71</property>
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="xalign">0</property>
                <property name="yalign">0</property>
                <property name="icon_name">accessories-text-editor</property>
              </object>
            </child>
          </object>
          <packing>
            <property name="x">200</property>
            <property name="y">20</property>
          </packing>
        </child>
        <child>
          <object class="GtkGrid" id="grid_test_parameter">
            <property name="width_request">582</property>
            <property name="height_request">116</property>
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="row_spacing">10</property>
            <property name="column_spacing">4</property>
            <child>
              <object class="GtkSwitch" id="switch_test_on">
                <property name="use_action_appearance">True</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <signal name="state-set" handler="on_switch_test_on_state_set" swapped="no"/>
              </object>
              <packing>
                <property name="left_attach">0</property>
                <property name="top_attach">0</property>
              </packing>
            </child>
          </object>
          <packing>
            <property name="x">15</property>
            <property name="y">245</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>

1 个答案:

答案 0 :(得分:0)

问题在于这两行:

gtk_builder_connect_signals (builder, toggle);
gtk_builder_connect_signals (builder, test);

使用此功能时,传递给用户连接信号的user_data将应用于所有信号处理程序。

如果您选择此路径,那么您的用户数据应包含所有相关数据,处理程序必须相应地处理它。

问题是你的信号处理程序期望不同的东西,但你给它们相同的数据。

来自gtk_builder_connect_signals

  

的user_data

     

用所有信号传回的用户数据

那你能做什么?

如果你想保持相同的方法,那么,让我们创建一个包含所有相关数据的结构,然后将其传递给回调/信号处理程序:

typedef struct {
   interface *toggle;
   test_parameters *test;
} app_user_data;

然后初始化内容:

app_user_data *user_data = g_slice_new (app_user_data);
user_data->toggle = toggle;
user_data->test = test;

删除多余的gtk_builder_connect_signals并将其替换为我们的新结构:

gtk_builder_connect_signals (builder, user_data);

现在,所有回调都可以使用他们需要的数据:

G_MODULE_EXPORT gboolean on_eventbox_image_wired_button_press_event (GtkWidget *widget, GdkEvent *event, gpointer toggle) {

   app_user_data *user_data = (app_user_data *) toggle;

    if (((interface *) user_data->toggle)->eth0 == NULL) {
        printf("%s\n", "WIRED: eth0 IS NULL - REMOVE ME");
    }
    ...

G_MODULE_EXPORT gboolean on_eventbox_image_wifi_button_press_event (GtkWidget *widget, GdkEvent *event, gpointer toggle) {
   app_user_data *user_data = (app_user_data *) toggle;

    /* Check to see if we have IP address so we can change the colour otherwise leave it red */
    if (((interface *) user_data->toggle)->wlan0->ip_enabled) {
    ...

G_MODULE_EXPORT gboolean on_switch_test_on_state_set (GtkSwitch *widget, gboolean state, gpointer test) {
   app_user_data *user_data = (app_user_data *) test;

   (((test_parameters *) user_data->test)->active) = state;
   ...

包含建议更改的代码应该是这样的:

/*
 *  * STRIPPED DOWN VERSION
 *   */
#include <arpa/inet.h>
#include <gtk/gtk.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>


#define IPV4_ENABLED                1
#define IPV4_DISABLED               0
#define SELECTED                    1

typedef struct {
    int ip_enabled;
} net;

typedef struct {
    net *eth0;
    net *wlan0;
    int type;
} interface;

typedef enum {
    IT_ETH0,
    IT_WLAN0,
    IT_UNASSIGNED = 999,
} interface_type;

typedef struct {
    int active;
    interface *port;
    int debug;
} test_parameters;

typedef struct {
   interface *toggle;
   test_parameters *test;
} app_user_data;

void wired (net *eth0);

void wifi (net *wlan0);

int main (int argc, char *argv[]) {

    GtkBuilder *builder;
    GtkWidget *window;
    GError *gtk_error = NULL;

    net *eth0 = g_slice_new (net);
    net *wlan0 = g_slice_new (net);
    interface *toggle = g_slice_new (interface);

    test_parameters *test = g_slice_new (test_parameters);

    test->port->type == IT_UNASSIGNED;

        /*Add interfaces to struct "interface" */
    toggle->eth0 = eth0;
    toggle->wlan0 = wlan0;

    toggle->eth0->ip_enabled = 0;
    toggle->wlan0->ip_enabled = 0;

   app_user_data *user_data = g_slice_new (app_user_data);
   user_data->toggle = toggle;
   user_data->test = test;

    if (NULL == toggle->eth0)
        fprintf (stdout, "%s\n", "eth0 is null ");

    if (NULL == toggle->wlan0)
        fprintf (stdout, "%s\n", "wlan0 is null ");


    gtk_init (&argc, &argv);

    builder = gtk_builder_new ();
    if (!gtk_builder_add_from_file (builder, "glade/window_main.glade", NULL)) {
        fprintf (stdout, "%s%s\n", "Error loading file with the reason: ", gtk_error->message);
        g_free (gtk_error);
        exit (EXIT_FAILURE);
    }

    window = GTK_WIDGET (gtk_builder_get_object (builder, "window_main"));

    gtk_builder_connect_signals (builder, user_data);

    g_object_unref (builder);

    wired (eth0);
    wifi (wlan0);
    gtk_widget_show (window);

    gtk_main ();

    g_slice_free (net, eth0);
    g_slice_free (net, wlan0);
    g_slice_free (interface, toggle);

    return 0;

}

void wifi (net *wlan0) {

    if (1) {
        wlan0->ip_enabled = IPV4_ENABLED;
    }

}

void wired (net *eth0) {

    if (1) {
        eth0->ip_enabled = IPV4_ENABLED;
    }

}

G_MODULE_EXPORT gboolean on_eventbox_image_wired_button_press_event (GtkWidget *widget, GdkEvent *event, gpointer toggle) {

   app_user_data *user_data = (app_user_data *) toggle;

    if (((interface *) user_data->toggle)->eth0 == NULL) {
        printf("%s\n", "WIRED: eth0 IS NULL - REMOVE ME");
    }

    if (((interface *) user_data->toggle) == NULL) {
        printf("%s\n", "WIRED: toggle IS NULL - REMOVE ME");
    }

    if (((interface *) user_data->toggle)->eth0->ip_enabled) {
        printf("%s\n", "WIRED: eth0 is ip enabled - REMOVE ME");
        ((interface *) toggle)->type = IT_ETH0;
        if (((interface *) user_data->toggle)->wlan0->ip_enabled) {
            printf("%s\n", "WIRED: wlan0 is ip enabled, adjust - REMOVE ME");
        }
    }
    return 0;
}

G_MODULE_EXPORT gboolean on_eventbox_image_wifi_button_press_event (GtkWidget *widget, GdkEvent *event, gpointer toggle) {
   app_user_data *user_data = (app_user_data *) toggle;

    /* Check to see if we have IP address so we can change the colour otherwise leave it red */
    if (((interface *) user_data->toggle)->wlan0->ip_enabled) {
        printf("%s\n", "WLAN has IP enabled");
        ((interface *) user_data->toggle)->type = IT_ETH0;
        if (((interface *) user_data->toggle)->eth0->ip_enabled) {
            printf("%s\n", "WLAN: eth0 is ip enabled, adjust - REMOVE ME");
        }
    }

    return 0;       
}

G_MODULE_EXPORT gboolean on_switch_test_on_state_set (GtkSwitch *widget, gboolean state, gpointer test) {
   app_user_data *user_data = (app_user_data *) test;

    (((test_parameters *) user_data->test)->active) = state;

    fprintf (stdout, "%s%i\n", "Signal fired and the state is ", state);

    return 0;

}

void on_window_main_destroy () {

    gtk_main_quit ();
}

它应该像以前一样编译而不是段错误。