GTK C SEGV:添加新信号原因SEGV



我将新的开关信号引入现有测试GUI。

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

此外,如果从新建运行,请先切换开关,然后单击事件框,还会导致SEGV(行为2)。两者的segv始终发生在同一位置(如果以事件框为例之一)如下:

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

我可以在代码方面提出的最简单的表现方式如下(abimecime):

/*
 * 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, "%sn", "eth0 is null ");
    if (NULL == toggle->wlan0)
        fprintf (stdout, "%sn", "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%sn", "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("%sn", "WIRED: eth0 IS NULL - REMOVE ME");
    }
    if (((interface *) toggle) == NULL) {
        printf("%sn", "WIRED: toggle IS NULL - REMOVE ME");
    }
    if (((interface *) toggle)->eth0->ip_enabled) {
        printf("%sn", "WIRED: eth0 is ip enabled - REMOVE ME");
        ((interface *) toggle)->type = IT_ETH0;
        if (((interface *) toggle)->wlan0->ip_enabled) {
            printf("%sn", "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("%sn", "WLAN has IP enabled");
        ((interface *) toggle)->type = IT_ETH0;
        if (((interface *) toggle)->eth0->ip_enabled) {
            printf("%sn", "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%in", "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>

问题位于这两行中:

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("%sn", "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, "%sn", "eth0 is null ");
    if (NULL == toggle->wlan0)
        fprintf (stdout, "%sn", "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%sn", "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("%sn", "WIRED: eth0 IS NULL - REMOVE ME");
    }
    if (((interface *) user_data->toggle) == NULL) {
        printf("%sn", "WIRED: toggle IS NULL - REMOVE ME");
    }
    if (((interface *) user_data->toggle)->eth0->ip_enabled) {
        printf("%sn", "WIRED: eth0 is ip enabled - REMOVE ME");
        ((interface *) toggle)->type = IT_ETH0;
        if (((interface *) user_data->toggle)->wlan0->ip_enabled) {
            printf("%sn", "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("%sn", "WLAN has IP enabled");
        ((interface *) user_data->toggle)->type = IT_ETH0;
        if (((interface *) user_data->toggle)->eth0->ip_enabled) {
            printf("%sn", "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%in", "Signal fired and the state is ", state);
    return 0;
}
void on_window_main_destroy () {
    gtk_main_quit ();
}

它应该像以前那样编译而不是segfault!

相关内容

  • 没有找到相关文章