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

GTK4 Windows多文件选择内存泄漏与崩溃问题求助

问题分析与修复方案

你的代码存在多个致命内存操作错误,直接引发段错误与GLib断言失败,以下是问题点及修复后的代码:

核心错误点

  • 未初始化的GtkTextIter指针:声明GtkTextIter *start;后未分配内存,直接传给gtk_text_buffer_get_start_iter会写入随机内存,触发内存损坏。
  • 字符串越界写入:sprintf(path, "%s\n", path);往g_file_get_path返回的固定长度字符串中追加换行符,破坏堆内存,导致GLib内部哈希表操作失败(即那些断言错误的根源)。
  • 未释放GFile实例:每次g_list_model_get_item获取的GFile对象未调用g_object_unref,造成内存泄漏。
  • 未释放GListModel:gtk_file_dialog_open_multiple_finish返回的GListModel用完后未调用g_object_unref。
  • path变量内存泄漏:循环中每次g_file_get_path返回的字符串未及时g_free,仅在最后释放一次,导致多次泄漏。
  • 提前释放GtkFileDialog:异步操作未完成就g_object_unref(fd),虽Gtk异步方法会临时持有引用,但规范做法是在回调中处理释放。

修复后的代码

static void
choseTargetFinish (GObject* source_object, GAsyncResult* res, gpointer data)
{
  GtkFileDialog *dialog = GTK_FILE_DIALOG (source_object);
  GError *error = NULL;
  GListModel *files = gtk_file_dialog_open_multiple_finish(dialog, res, &error);
  
  if (error != NULL) {
    g_warning("Failed to open files: %s", error->message);
    g_error_free(error);
    g_object_unref(dialog);
    return;
  }

  if (files != NULL)
  {
    // 使用栈上的GtkTextIter实例,替代未初始化的指针
    GtkTextIter start, end;
    gtk_text_buffer_get_start_iter(targetPathBuffer, &start);
    gtk_text_buffer_get_end_iter(targetPathBuffer, &end);
    gtk_text_buffer_delete(targetPathBuffer, &start, &end);

    guint n_items = g_list_model_get_n_items(files);
    for (guint i = 0; i < n_items; i++)
    {
      GFile *file = g_list_model_get_item(files, i);
      if (file == NULL) continue;

      char *path = g_file_get_path(file);
      if (path != NULL) {
        // 用g_strconcat安全拼接换行符,避免越界
        char *path_with_newline = g_strconcat(path, "\n", NULL);
        gtk_text_buffer_insert(targetPathBuffer, &end, path_with_newline, -1);
        gtk_text_buffer_get_end_iter(targetPathBuffer, &end);
        g_free(path_with_newline);
        g_free(path);
      }
      
      // 释放GFile对象
      g_object_unref(file);
    }

    // 释放GListModel
    g_object_unref(files);
  }

  // 在回调末尾释放对话框对象
  g_object_unref(dialog);
}

static void
chooseTarget_cb (GtkWidget *widget)
{
  GtkFileDialog *fd = gtk_file_dialog_new();
  gtk_file_dialog_open_multiple(fd, NULL, NULL, choseTargetFinish, NULL);
  // 不再提前unref,交给回调处理释放
}

关键修改说明

  1. GtkTextIter改为栈实例:用GtkTextIter start, end;替代指针,传地址给gtk_text_buffer_get_*_iter,避免野指针访问。
  2. 安全拼接字符串:用g_strconcat创建带换行符的新字符串,不破坏原路径字符串的内存。
  3. 循环内释放资源:每次获取的GFile和path都在循环内释放,避免内存泄漏。
  4. 添加错误处理:用GError捕获异步操作错误,便于调试。
  5. 规范释放对话框:将g_object_unref(dialog)放在回调末尾,确保异步操作完成后再释放对象。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 10:05:13