释放时填充结构数据会导致段错误

Posted

技术标签:

【中文标题】释放时填充结构数据会导致段错误【英文标题】:populating struct data causes a segfault when freed 【发布时间】:2021-09-18 23:42:10 【问题描述】:

我有一些简单的代码可以创建一个新结构(包含一个字符串和一个长度),然后删除该结构。

/* string/proc.c */

#include "proc.h" /* String */
#include <malloc.h>
#include <assert.h>
#include <stddef.h> /* NULL */

struct string 
        char* str;
        int   len;
;


String new_string (int length)

        String S;
        S = (String) malloc (sizeof (String));
        S ->str = (char*) malloc (sizeof (char*) * length + 1);
        S ->str [length] = '\0';
        S ->len = length;

        return S;



void delete_string (String *Sp)

        free ((*Sp) ->str);
        free (*Sp);
        *Sp = NULL;


/* end of file */

这些函数是通过一个头文件暴露出来的,结构是typedef的。

/* string/proc.h */
#ifndef string_proc_h
#define string_proc_h

typedef struct string* String;

String new_string (int length);
void delete_string (String*);

#endif
/* end of file */

我还有一个测试文件,其中#include 是那个头文件并测试新功能和删除功能:

/* string/proc_test.c */

#include "proc.h"
#include <assert.h>
#include <stddef.h> /* NULL */

int test_new_string ()

        int ok = 0;

        String S = new_string (10);
        assert (S);
        ok ++;

        delete_string (&S);

        return ok;



int test_delete_string ()

        int ok = 0;

        String S = new_string (10);
        delete_string (&S);
        assert (S == NULL);
        ok ++;

        return ok;


/* end of file */

问题:当我运行这个程序时,我得到一个分段错误(核心转储)。

我可以在这一行使用 dbg 跟踪到 proc.c 文件:

*Sp = NULL;

但是:

当我从 proc.c 文件中删除 this 行时:

S ->len = length;

...两个测试都通过了!

为什么程序运行良好,通过了测试,但是当我尝试对范围内的结构进行更改时,它会导致我的代码中看似不相关的部分出现段错误?

我没有看到这些是什么关系...你能帮帮我吗?

【问题讨论】:

你试过使用 valgrind 吗? typedef struct string* String; 只会导致悲伤。 不,我没有尝试过使用 valgrind——我不熟悉这个工具,但我会试一试。是的,我很难过。 【参考方案1】:

线条

        S = (String) malloc (sizeof (String));
        S ->str = (char*) malloc (sizeof (char*) * length + 1);

错了。应该是:

        S = malloc (sizeof (*S));
        S ->str = malloc (sizeof (*(S->str)) * length + 1);

        S = malloc (sizeof (struct string));
        S ->str = malloc (sizeof (char) * length + 1);

第一行是致命的。它只分配一个指针,而需要分配结构。第二行不是致命的,但它会分配一些额外的内存,因为它为每个元素分配一个指针,而只需要一个字符的空间。

还要注意malloc() family 的转换结果是considered as a bad practice。

另一个建议是你不应该使用typedef 来隐藏这样的指针,因为它会使它更加混乱。

【讨论】:

很好——这是一个愚蠢的错误。感谢您提供有关强制转换的链接——我正在使用 c++compat 标志,所以我需要它,但我应该意识到危险。我假设您的意思是我应该使用 typedef struct string String,然后使用 String* 访问它,而不是 typedef struct string* String 和 String,对吗?

以上是关于释放时填充结构数据会导致段错误的主要内容,如果未能解决你的问题,请参考以下文章

为啥释放内存会导致分段错误?

在 OpenGL 中为索引缓冲区对象使用结构会导致段错误

为啥无限递归会导致段错误

尝试初始化结构数组时出现段错误

将结构插入地图时出现分段错误

从共享内存段复制数据会导致客户端出现段错误(信号量和共享内存)