使用 memset 和 freeaddrinfo 会导致双重释放或损坏错误

Posted

技术标签:

【中文标题】使用 memset 和 freeaddrinfo 会导致双重释放或损坏错误【英文标题】:using memset and freeaddrinfo causes the double free or corruption error 【发布时间】:2021-07-18 15:40:03 【问题描述】:

src.cpp

#include <iostream>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

int main()
  
    struct addrinfo hints, *servinfo;
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE;
    getaddrinfo(NULL, "1560", &hints, &servinfo);
    freeaddrinfo(&hints);



我用gdb找出错误发生在哪里,它发生在memset 但是当我注释掉对 freeaddrinfo() 的调用时,它没有给出错误并且可以正常工作!

我正在运行 Ubuntu 20.04.2 内核 5.8.0-55-generic

编辑: 正如您指出的,我应该给 freeaddrinfo 一个由 getaddrinfo 提供的列表,当我将 servinfo 传递给 freeaddrinfo 时,它会给出以下错误

double free or corruption (out)
[1]    4123 abort (core dumped)  ./a.out

编辑 2:谢谢,在编辑问题时,我忘记用 servinfo 替换 &hints,并认为我已经替换了它,很抱歉给您带来不便,我的愚蠢值得一票否决。

【问题讨论】:

你可以试试valgrind 【参考方案1】:

freeaddrinfo 函数需要一个指向由getaddrinfo 创建的addrinfo 结构列表的指针。

你传递的指针不是这样的结构列表,所以会导致函数内部的未定义行为


getaddrinfo 函数很可能使用malloc 分配结构,freeaddr 函数将它们传递给free

您不能传递指向free 的指针,而该指针不是由malloc(或其他相关函数,如callocrealloc)返回的。


您不会为hints 动态分配空间。您在堆栈上分配它。它不应该传递给freeaddrinfo,只有结果(在你的情况下是servinfo)应该是。

【讨论】:

正如你所指出的,我应该给 freeaddrinfo 一个由 getaddrinfo 提供的列表,当我将 servinfo 传递给 freeaddrinfo 时,它会给出双重免费或损坏错误:( @HPSmash77 只是不要打电话给freeaddrinfo(&amp;hints)?作为一般提示:当您在调用包含术语free 的任何函数时需要使用指向(或地址)运算符&amp; 时,您应该将其视为您做错了什么的标志。 【参考方案2】:
freeaddrinfo(&hints);

这是预期的行为(行为未定义的方式;而不是您可以依赖此行为的方式)。您只能将getaddrinfo 创建的结构传递给freeaddrinfo。您没有使用getaddrinfo 创建&amp;hints。不要将hints 传递给freeaddrinfo

一个固定的例子:

addrinfo hints 
    .ai_flags    = AI_PASSIVE,
    .ai_family   = AF_UNSPEC,
    .ai_socktype = SOCK_STREAM,
;
addrinfo* result;
int err = getaddrinfo(nullptr, "12345", &hints, &result);
if (err) 
    std::cout << "getaddrinfo: " << gai_strerror(err);
    std::exit(EXIT_FAILURE);
 else 
    // use it here

    freeaddrinfo(result); // pay particular attention to this

我把它换成了 freeaddrinfo(servinfo);

您的新示例仍然有freeaddrinfo(&amp;hints),但也有freeaddrinfo(servinfo)。如果您将前者替换为后者,那么您将调用freeaddrinfo(servinfo) 两次。释放后,您不能使用无效的servinfo,包括第二次将其传递给freeaddrinfo。类似的规则适用于std::free

【讨论】:

正如你所指出的,我应该给 freeaddrinfo 一个由 getaddrinfo 提供的列表,当我将 servinfo 传递给 freeaddrinfo 时,它会给出双重免费或损坏错误:( @HPSmash77 你必须删除freeaddrinfo(&amp;hints);这一行 我把它换成了 freeaddrinfo(servinfo);然后它给出了我在上一条评论中指定的错误 @HPSmash77 见编辑。另请参阅我的示例。 哦!抱歉,编辑代码时忘记这样做了:(

以上是关于使用 memset 和 freeaddrinfo 会导致双重释放或损坏错误的主要内容,如果未能解决你的问题,请参考以下文章

使用 D 切片的 memset() 和 memcpy()

使用 memset 和 int 值初始化整数数组 - 失败

对二维数组的“memset”的混淆和“free”的错误

memset使用误区

各种memset函数使用方式的区别

malloc、memset 和免费的正确用法