realloc-内存泄漏

realloc-内存泄漏,c,memory-management,realloc,C,Memory Management,Realloc,我得到了一些C代码: typedef struct { size_t len; size_t alloclen; char *buf; } str; void strnappnd(str **s, const char *buf, size_t n) { if ((*s)->len + n >= (*s)->alloclen) { size_t nalloclen = (*s)->len + n + 1;

我得到了一些C代码:

typedef struct {
    size_t len;
    size_t alloclen;
    char *buf;
} str;

void strnappnd(str **s, const char *buf, size_t n) {

    if ((*s)->len + n >= (*s)->alloclen) {
        size_t nalloclen = (*s)->len + n + 1;
        void *tmp = realloc((*s)->buf, nalloclen);
        if (!tmp) {
            printf("failure");
            exit(-1);
        }
        (*s)->buf = tmp;
        (*s)->alloclen = nalloclen;
    }
    memccpy((*s)->buf + (*s)->len, buf, '\0', n);
    (*s)->len += n;
    (*s)->buf[(*s)->len] = '\0';
}

void strfree(str **s) {
    free((*s)->buf);
    free(*s);
    *s = NULL;
}
显然,strnappnd在realloc管线处泄漏。为什么?

考虑一下:

void f() {
  str *s = (str *)malloc(sizeof(str));
  s->len = 5;
  s->alloclen = 5;
  s->buf = strdup("Hello");
  strnappend(&s, " World!", 7);
  free(s); /* courtesy of Eric */
}
如果您有类似的情况,则
realloc()
分配的内存会随着
f()
的剩余而泄漏。

考虑:

void f() {
  str *s = (str *)malloc(sizeof(str));
  s->len = 5;
  s->alloclen = 5;
  s->buf = strdup("Hello");
  strnappend(&s, " World!", 7);
  free(s); /* courtesy of Eric */
}
如果您有类似的东西,则
realloc()
分配的内存会泄漏,因为
f()
被保留。

如果您编写

(*s)->buf = realloc((*s)->buf, nalloclen)
这将是内存泄漏,因为如果
realloc
失败并返回
NULL
,您将丢失
(*s)->buf
指针,该指针仍指向已分配的内存

由于您在出现故障时退出,这不是问题,但是如果您编写了

(*s)->buf = realloc((*s)->buf, nalloclen)
这将是内存泄漏,因为如果
realloc
失败并返回
NULL
,您将丢失
(*s)->buf
指针,该指针仍指向已分配的内存

由于您在出现故障时退出,这不是问题,但您的静态分析器可能会忽略退出?

,就像mtrace所说的“无内存泄漏”

使用Frerich给出的示例代码

void f() {
  str *s = (str *)malloc(sizeof(str));
  s->len = 5;
  s->alloclen = 5;
  s->buf = strdup("Hello");
  s->buf = strnappend(&s, " World!", 7);
  strfree(s);
}
就像mtrace说的“没有内存泄漏”

使用Frerich给出的示例代码

void f() {
  str *s = (str *)malloc(sizeof(str));
  s->len = 5;
  s->alloclen = 5;
  s->buf = strdup("Hello");
  s->buf = strnappend(&s, " World!", 7);
  strfree(s);
}
您创建了strfree()函数,但在代码中没有使用它。 如果不使用内存,则需要始终释放内存

if (!tmp) {
    printf("failure");
    if (!(*s) && !((*s)->buf))
       strfree(&(*s));
    exit(-1);
}
查找strfree(),看起来您在某处也为*s保留了内存。 在代码完成之前执行同样的操作

if (!(*s) && !((*s)->buf))
   strfree(&(*s));
您创建了strfree()函数,但在代码中没有使用它。 如果不使用内存,则需要始终释放内存

if (!tmp) {
    printf("failure");
    if (!(*s) && !((*s)->buf))
       strfree(&(*s));
    exit(-1);
}
查找strfree(),看起来您在某处也为*s保留了内存。 在代码完成之前执行同样的操作

if (!(*s) && !((*s)->buf))
   strfree(&(*s));


@user282635在最终的realloc之后,您是否最终释放了
(*s)->buf
。@aix:我认为使用realloc意味着您不需要释放缓冲区。您如何检测泄漏?重要的是,当已经有足够的空间时,不会追加字符串。三点:1)函数名不能以“str”开头,这是一个保留的名称空间;2)考虑将缓冲区增长超过1个字节,如果这是通用的,可以更好地摊销多个附件的成本;3) 正如@pmg所说,对于缓冲区足够大的情况,似乎缺少代码。将其从realloc()路径中分离出来。@user282635您最终是否释放了
(*s)->buf
在最后一个realloc之后?@aix:我认为使用realloc意味着您不需要释放缓冲区。您如何检测泄漏?重要的是,当已经有足够的空间时,不会追加字符串。三点:1)函数名不能以“str”开头,这是一个保留的名称空间;2)考虑将缓冲区增长超过1个字节,如果这是通用的,可以更好地摊销多个附件的成本;3) 正如@pmg所说,对于缓冲区足够大的情况,似乎缺少代码。将它从realloc()路径中分离出来。还有
malloc()
分配的内存。我认为更好的例子是在堆栈上分配
str
的实例。@Erik:我认为就内存检查器而言,
malloc()
调用分配的内存将与
realloc()相关联
打电话。所以从技术上讲,就内存检查器而言,只有
realloc()
泄漏(同样,我只是猜测)。我认为这是因为
realloc()
由于内存碎片,可能无法扩展已经分配的内存块大小。相反,它可能必须释放内存并分配一个请求大小的全新块。@Frerich:我在您的第一行中谈到malloc:)@Frerich:不,realloc是在
s->buf
上调用的,而不是在
s
本身上调用的。内存是由
malloc()分配的
也是。我认为更好的例子是在堆栈上分配
str
的实例。@Erik:我认为就内存检查器而言,
malloc()
调用分配的内存将与
realloc()
调用相关联。所以从技术上讲,就内存检查器而言,只有
realloc()
泄漏(同样,我只是猜测)。我认为这是因为
realloc()
由于内存碎片,可能无法扩展已经分配的内存块大小。相反,它可能必须释放内存并分配一个请求大小的全新块。@Frerich:我在您的第一行中谈论malloc:)@Frerich:不,realloc是在
s->buf
上调用的,而不是
s
本身。@user282635–是什么告诉您
realloc
泄漏的?某种静态分析仪?Valgrind?不,我在循环中运行代码(几乎就是我发布的代码),内存使用量不断增长…@user282635–你应该发布程序的其余部分,因为这两个函数中的内存处理看起来很好。@user282635–什么告诉你
realloc
泄漏了?某种静态分析仪?Valgrind?不,我在循环中运行代码(几乎就是我发布的代码),内存使用量不断增长…@user282635–您应该发布程序的其余部分,因为这两个函数中的内存处理看起来不错。