为GLib的GSList定义free_func出错,求助内存释放问题
GSList释放Test结构体时
free(t->b)报错的排查与解决 我有一个存储Test结构体的GSList,结构体定义如下:
typedef struct test { char *a; char *b; char *c; } Test;
使用g_slist_free_full释放列表时,自定义的free_test函数总是在free(t->b)处失败,报错包括free(): invalid pointer、Segmentation fault、munmap_chunk(): invalid pointer,而且释放t->a后打印t->b会发现首字符被修改。
我的free_test实现:
void free_test(void *test) { Test *t = (Test *)test; free(t->a); free(t->b); free(t->c); free(t); }
可能的原因及解决步骤
1. 字符串指针指向非堆内存
如果t->b指向的是字符串字面量(比如直接赋值test->b = "hello")或者栈上的局部变量,调用free会触发非法指针错误——因为free只能释放堆上用malloc/calloc/realloc分配的内存。
解决:
- 确保所有字符串成员都是通过动态内存分配函数创建的,比如:
test->b = g_strdup("hello"); // 用GLib的g_strdup,或者malloc+strcpy - 如果某些成员可能为NULL,释放前先判断:
void free_test(void *test) { Test *t = (Test *)test; if (t->a) free(t->a); if (t->b) free(t->b); if (t->c) free(t->c); free(t); }
2. 内存重复释放
如果t->a和t->b指向同一块内存(比如误写test->b = test->a),释放t->a后,t->b就变成了野指针,再次free就会报错。另外,如果代码中其他地方已经释放过t->b,也会导致这个问题。
解决:
- 检查结构体初始化和赋值逻辑,确保每个字符串成员指向独立的堆内存,或者释放后置空指针避免重复释放:
free(t->a); t->a = NULL; free(t->b); t->b = NULL;
3. 内存越界覆盖指针
如果在写入t->a时发生内存越界(比如t->a分配的空间不够,却写入了过长的字符串),会覆盖t->b的指针值,导致t->b变成无效指针。这也能解释为什么释放t->a后t->b的内容被修改——越界已经破坏了t->b的存储。
解决:
- 确保字符串分配的空间足够容纳内容+结束符
\0,比如用strlen(str)+1计算所需长度:const char *src = "long string"; test->a = malloc(strlen(src) + 1); strcpy(test->a, src); - 用GLib的安全字符串函数(比如
g_strdup、g_strlcpy)替代手动分配,避免越界。
4. Test结构体本身的内存问题
如果Test结构体不是用malloc/g_malloc动态分配的(比如是栈上的局部变量),调用free(t)会破坏堆结构,进而影响后续的free操作。
解决:
- 确保添加到GSList的每个Test实例都是动态分配的:
Test *new_test = malloc(sizeof(Test)); // 初始化new_test的成员 g_slist_append(list, new_test);
内容的提问来源于stack exchange,提问作者CarlosHSF
相关产品推荐
相关产品推荐

