You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GTK 3程序在Windows正常运行,Linux调用gtk_combo_box_text_remove时崩溃

问题描述

我正在为大学项目开发一款C语言程序,用SQLite3处理数据库,GTK3构建GUI。使用GtkComboBoxText控件,通过gtk_combo_box_text_append()和gtk_combo_box_text_remove()添加、移除下拉选项。
调用gtk_combo_box_text_remove()时程序崩溃,但仅在Linux系统出现此问题,Windows下完全正常。该函数只接收GtkComboBoxText指针和待移除选项的索引值作为参数。

用Valgrind检测到以下内存错误:

==30432== Invalid read of size 1
==30432==    at 0x7D08730: __strcpy_sse2_unaligned (in /lib64/libc-2.26.so)
==30432==    by 0x405A70: on_combo_changed (main.c:981)
==30432==    by 0x72D7E95: ??? (in /usr/lib64/libgobject-2.0.so.0.6200.6)
==30432==    by 0x72F447B: g_signal_emit_valist (in /usr/lib64/libgobject-2.0.so.0.6200.6)
==30432==    by 0x72F49CE: g_signal_emit (in /usr/lib64/libgobject-2.0.so.0.6200.6)
==30432==    by 0x52DAF1B: ??? (in /usr/lib64/libgtk-3.so.0.2404.16)
==30432==    by 0x72D7C5C: g_closure_invoke (in /usr/lib64/libgobject-2.0.so.0.6200.6)
==30432==    by 0x72EB84D: ??? (in /usr/lib64/libgobject-2.0.so.0.6200.6)
==30432==    by 0x72F404B: g_signal_emit_valist (in /usr/lib64/libgobject-2.0.so.0.6200.6)
==30432==    by 0x72F49CE: g_signal_emit (in /usr/lib64/libgobject-2.0.so.0.6200.6)
==30432==    by 0x53B0758: gtk_list_store_remove (in /usr/lib64/libgtk-3.so.0.2404.16)
==30432==    by 0x52DEEB8: gtk_combo_box_text_remove (in /usr/lib64/libgtk-3.so.0.2404.16)
==30432==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==30432==
==30432==
==30432== Process terminating with default action of signal 11 (SIGSEGV): dumping core

尝试增大栈空间等方法均无效。

补充:可复现的精简代码

已用精简代码复现问题,Valgrind报错相同,同样Windows正常、Linux崩溃。

测试代码

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

GtkBuilder *builder;
GtkWidget *window;
GtkWidget *fixed;
GtkWidget *button;
GtkWidget *label;
GtkComboBoxText *combo;

char active[100];
int foo = 0;

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

  gtk_init(&argc, &argv);

  builder = gtk_builder_new_from_file("test.glade");
  window = GTK_WIDGET(gtk_builder_get_object(builder, "window"));
  fixed = GTK_WIDGET(gtk_builder_get_object(builder, "fixed"));
  combo = GTK_COMBO_BOX_TEXT(gtk_builder_get_object(builder, "combo"));
  button = GTK_WIDGET(gtk_builder_get_object(builder, "button"));
  label = GTK_WIDGET(gtk_builder_get_object(builder, "label"));
  gtk_builder_connect_signals(builder, NULL);
  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ALWAYS);

      gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "something");
      gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "something 2");

  gtk_widget_show_all(window);

  gtk_main();

  return EXIT_SUCCESS;

}

void on_button_clicked () {

    gtk_combo_box_text_remove(combo, foo);
    
}
       

void on_combo_changed () {

    sprintf(active, "%s", gtk_combo_box_text_get_active_text(combo));
    foo = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));

}

Glade文件

<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.40.0 -->
<interface>
  <requires lib="gtk+" version="3.24"/>
  <object class="GtkWindow" id="window">
    <property name="width-request">400</property>
    <property name="height-request">200</property>
    <property name="can-focus">False</property>
    <property name="default-width">400</property>
    <property name="default-height">200</property>
    <child>
      <!-- n-columns=1 n-rows=3 -->
      <object class="GtkGrid" id="grid">
        <property name="width-request">400</property>
        <property name="height-request">200</property>
        <property name="visible">True</property>
        <property name="can-focus">False</property>
        <child>
          <object class="GtkButton" id="button">
            <property name="label" translatable="yes">button</property>
            <property name="width-request">400</property>
            <property name="height-request">60</property>
            <property name="visible">True</property>
            <property name="can-focus">True</property>
            <property name="receives-default">True</property>
            <signal name="clicked" handler="on_button_clicked" swapped="no"/>
          </object>
          <packing>
            <property name="left-attach">0</property>
            <property name="top-attach">2</property>
          </packing>
        </child>
        <child>
          <object class="GtkLabel" id="label">
            <property name="width-request">400</property>
            <property name="height-request">60</property>
            <property name="visible">True</property>
            <property name="can-focus">False</property>
            <property name="label" translatable="yes">example</property>
          </object>
          <packing>
            <property name="left-attach">0</property>
            <property name="top-attach">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkComboBoxText" id="combo">
            <property name="width-request">400</property>
            <property name="height-request">80</property>
            <property name="visible">True</property>
            <property name="can-focus">False</property>
            <signal name="changed" handler="on_combo_changed" swapped="no"/>
          </object>
          <packing>
            <property name="left-attach">0</property>
            <property name="top-attach">1</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>

编译命令

gcc -g -Wall -Wextra -o main main.c `pkg-config --cflags --libs gtk+-3.0 gmodule-2.0`

请问这是代码问题还是GTK的bug?


问题分析与解决方案

这是代码逻辑问题,并非GTK的bug。问题出在on_combo_changed信号处理函数中:

  • 调用gtk_combo_box_text_remove()移除选项时,GTK会触发changed信号。如果被移除的是当前选中的选项,下拉框会自动将选中状态设为无选中项(此时gtk_combo_box_get_active()返回-1)。
  • 此时on_combo_changed被调用,gtk_combo_box_text_get_active_text(combo)会返回NULL(因为没有选中项),但代码直接把NULL传给sprintf的%s格式符,导致访问空指针,触发段错误。
  • Windows下可能因内存布局或GTK行为差异(比如移除选中项后默认选中第一个剩余选项)未触发该场景,但Linux下GTK的行为符合规范:移除选中项后无选中状态,返回NULL。

修复方法

在on_combo_changed中先检查gtk_combo_box_text_get_active_text()的返回值是否为NULL,再进行字符串拷贝:

void on_combo_changed () {
    const gchar *text = gtk_combo_box_text_get_active_text(combo);
    if (text != NULL) {
        g_strlcpy(active, text, sizeof(active)); // 用g_strlcpy更安全,避免缓冲区溢出
    } else {
        active[0] = '\0'; // 清空字符串或做其他处理
    }
    foo = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
}

另外,on_button_clicked中移除选项时,需确保foo是有效的索引(比如移除最后一个选项后,foo可能变成无效值),可添加索引有效性检查:

void on_button_clicked () {
    gint count = gtk_combo_box_text_get_length(combo);
    if (foo >= 0 && foo < count) {
        gtk_combo_box_text_remove(combo, foo);
    }
}

这样即可避免Linux下的崩溃问题,同时让代码更健壮,符合GTK的API规范。


内容的提问来源于stack exchange,提问作者Edward Teller

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 14:27:35