C addrinfo结构已损坏。但heap仍然有效

C addrinfo结构已损坏。但heap仍然有效,c,winsock,memory-corruption,C,Winsock,Memory Corruption,我尝试创建一个套接字并连接到远程主机。我使用GetAddrInfo从域解析远程主机。这很好用。调用之后,我得到一个具有正确值的addrinfo结构。但在某些情况下,结构在调用connect()之前会损坏 因此,这在我的四核Win10笔记本电脑上运行良好。但如果我加上一个例子 MessageBoxA(NULL, "After sock", "HTTP", MB_ICONWARNING|MB_CANCELTRYCONTINUE | MB_DEFBUTTON2); 在connect()调用之前调用,

我尝试创建一个套接字并连接到远程主机。我使用GetAddrInfo从域解析远程主机。这很好用。调用之后,我得到一个具有正确值的addrinfo结构。但在某些情况下,结构在调用connect()之前会损坏

因此,这在我的四核Win10笔记本电脑上运行良好。但如果我加上一个例子

MessageBoxA(NULL, "After sock", "HTTP", MB_ICONWARNING|MB_CANCELTRYCONTINUE | MB_DEFBUTTON2);
在connect()调用之前调用,并在调试器中检查addrinfo结构,如果该结构已损坏。例如,有一段时间我可以看到ai_canonname应该是“google.com”被“After Sock”覆盖。但在此之后,堆仍然有效。 所以我不知道从哪里开始调试这个。可能是其他缓冲区或结构溢出到某处吗

每次执行line
res=res->ai\u next时,while(res)将指针移动到原始节点以外的其他节点
,但随后调用
FreeAddrInfo(res)位于修改指针的末尾,而不是通过GetAddrInfo分配的指针


另外,虽然您没有提供lookup_host函数的开始,但是假设inout是ptr,您将它设置为分配的emory中sin_addr的地址,然后在函数结束时释放内存,因此,它可能被其他东西使用。

这是因为在使用它之前,您释放了与结果相关的所有内存。例如,
ai\u canonname
是指向从堆中分配的字符串的指针。在退出
lookup\u host
之前,包含其字节的内存被标记为可重用。您的
CopyMemory
将复制指针,但不会复制指针指向的字节

注意:您应该发布整个
lookup\u host
,包括函数定义

您需要找到一种避免调用
FreeAddrInfo
的方法,直到完成之后。或者做一个更深层次的
struct
复制,包括所有指向的东西,你会发现它们很快就会变成一个兔子洞

我要做的是提供一个回调函数,在
lookup\u host

内调用该函数时,您的
lookup\u host()
没有将地址数据正确返回给调用方,甚至没有关闭
addrinfo
包含指向
addrinfo
外部数据的指针。但是您只是将
addrinfo
本身复制到调用者,而不是它所指向的任何数据

请尝试类似以下内容:

int lookup_host(const wchar_t *host, int family, void *sa)
{
    struct addrinfoW hints;
    struct addrinfoW *res, *addr;
    int errcode, addrlen, returnval;
    void *ptr;

    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = family;
    hints.ai_socktype = SOCK_STREAM;

    errcode = GetAddrInfoW(host, L"80", &hints, &res);
    //GetAddrInfoExW(host, L"80", NS_ALL, NULL, &hints, &res, NULL, NULL, NULL, NULL);
    if (errcode != 0)
    {
        //perror("getaddrinfo");
        return -1;
    }

    returnval = 0;

    for(addr = res; addr != NULL; addr = addr->ai_next)
    {
        switch (addr->ai_family)
        {
            case AF_INET:
                ptr = &((struct sockaddr_in *) addr->ai_addr)->sin_addr;
                addrlen = sizeof(struct sockaddr_in);
                break;

            case AF_INET6:
                ptr = &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;
                addrlen = sizeof(struct sockaddr_in6);
                break;

            default:
                continue;
        }

        CopyMemory(sa, ptr, addrlen);
        returnval = 1;
        break;
    }

    FreeAddrInfoW(res);

    return returnval;
}

...

struct sockaddr_in sa;

if (lookup_host(host, AF_INET, &sa) != 1) {
    return -1;
}

SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == INVALID_SOCKET) {
    return -1;
}

if (connect(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
    #ifdef _DEBUG
    printf("Error: %d\n", GetLastError());
    #endif // _DEBUG

    closesocket(sock);
    return -2;
}

...
int lookup_host(常量wchar_t*host,int族,void*sa)
{
结构addrinfoW提示;
结构addrinfoW*res,*addr;
int errcode、addrlen、returnval;
无效*ptr;
零内存(&提示,sizeof(提示));
hits.ai_family=家庭;
hits.ai_socktype=SOCK_流;
errcode=GetAddrInfoW(主机、L“80”、提示和res);
//GetAddrInfoExW(主机,L“80”,NS_ALL,NULL,&提示,&res,NULL,NULL,NULL,NULL);
如果(错误代码!=0)
{
//perror(“getaddrinfo”);
返回-1;
}
returnval=0;
for(addr=res;addr!=NULL;addr=addr->ai_next)
{
开关(地址->人工智能系列)
{
案例分析:
ptr=&((结构sockaddr_in*)addr->ai_addr)->sin_addr;
addrlen=sizeof(结构sockaddr_in);
打破
案例6:
ptr=&(结构sockaddr\u in6*)res->ai\u addr->sin6\u addr;
addrlen=sizeof(结构sockaddr_in6);
打破
违约:
继续;
}
CopyMemory(sa、ptr、addrlen);
returnval=1;
打破
}
FreeAddrInfoW(res);
返回值;
}
...
sa中的结构sockaddr_;
如果(查找主机(主机、AF主机和sa)!=1){
返回-1;
}
SOCKET sock=SOCKET(AF_INET、sock流、IPPROTO_TCP);
if(sock==无效的_套接字){
返回-1;
}
if(connect(sock,(struct sockaddr*)&sa,sizeof(sa))<0){
#ifdef_调试
printf(“错误:%d\n”,GetLastError());
#endif/\u调试
插座;
返回-2;
}
...
但是,请注意,上面只返回找到的第一个地址。主机名可以解析为多个IP,而您的电脑可能没有到所有IP的路由。因此,您应该尝试连接到报告的每个地址,直到其中一个成功,例如:

int lookup_host(const wchar_t *host, int family, struct addrinfoW **addrs)
{
    struct addrinfoW hints;
    int errcode;

    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = family;
    hints.ai_socktype = SOCK_STREAM;

    errcode = GetAddrInfoW(host, L"80", &hints, addrs);
    //GetAddrInfoExW(host, L"80", NS_ALL, NULL, &hints, addrs, NULL, NULL, NULL, NULL);
    if (errcode != 0)
    {
        //perror("getaddrinfo");
        return -1;
    }

    return 0;
}

...

struct addrInfoW *res, *addr;

if (lookup_host(host, AF_INET, &res) < 0) { // or AF_INET6, or AF_UNSPEC
    return -1;
}

sock = INVALID_SOCKET;

for(addr = res; addr != NULL; addr = addr->ai_next)
{
    sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
    if (sock == INVALID_SOCKET) {
        break;
    }

    if (connect(sock, addr->ai_addr, addr->ai_addrlen) == 0) {
        break;
    }

    #ifdef _DEBUG
    printf("Error: %d\n", GetLastError());
    #endif // _DEBUG

    closesocket(sock);
    sock = INVALID_SOCKET;
}

FreeAddrInfoW(res);

if (sock == INVALID_SOCKET) {
    return -2;
}

...
int lookup\u host(常量wchar\u t*host,int族,结构addrinfoW**addrs)
{
结构addrinfoW提示;
内码;
零内存(&提示,sizeof(提示));
hits.ai_family=家庭;
hits.ai_socktype=SOCK_流;
errcode=GetAddrInfoW(主机,L“80”&提示,地址);
//GetAddrInfoExW(主机,L“80”,NS_ALL,NULL,&提示,addrs,NULL,NULL,NULL,NULL);
如果(错误代码!=0)
{
//perror(“getaddrinfo”);
返回-1;
}
返回0;
}
...
结构addrInfoW*res,*addr;
if(lookup_host(host,AF_INET,&res)<0){//或AF_INET6,或AF_unsec
返回-1;
}
sock=无效的_插座;
for(addr=res;addr!=NULL;addr=addr->ai_next)
{
sock=socket(addr->ai_族,addr->ai_socktype,addr->ai_协议);
if(sock==无效的_套接字){
打破
}
如果(连接(sock,addr->ai_addr,addr->ai_addrlen)==0){
打破
}
#ifdef_调试
printf(“错误:%d\n”,GetLastError());
#endif/\u调试
插座;
sock=无效的_插座;
}
FreeAddrInfoW(res);
if(sock==无效的_套接字){
返回-2;
}
...
int lookup_host(const wchar_t *host, int family, void *sa)
{
    struct addrinfoW hints;
    struct addrinfoW *res, *addr;
    int errcode, addrlen, returnval;
    void *ptr;

    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = family;
    hints.ai_socktype = SOCK_STREAM;

    errcode = GetAddrInfoW(host, L"80", &hints, &res);
    //GetAddrInfoExW(host, L"80", NS_ALL, NULL, &hints, &res, NULL, NULL, NULL, NULL);
    if (errcode != 0)
    {
        //perror("getaddrinfo");
        return -1;
    }

    returnval = 0;

    for(addr = res; addr != NULL; addr = addr->ai_next)
    {
        switch (addr->ai_family)
        {
            case AF_INET:
                ptr = &((struct sockaddr_in *) addr->ai_addr)->sin_addr;
                addrlen = sizeof(struct sockaddr_in);
                break;

            case AF_INET6:
                ptr = &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;
                addrlen = sizeof(struct sockaddr_in6);
                break;

            default:
                continue;
        }

        CopyMemory(sa, ptr, addrlen);
        returnval = 1;
        break;
    }

    FreeAddrInfoW(res);

    return returnval;
}

...

struct sockaddr_in sa;

if (lookup_host(host, AF_INET, &sa) != 1) {
    return -1;
}

SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == INVALID_SOCKET) {
    return -1;
}

if (connect(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
    #ifdef _DEBUG
    printf("Error: %d\n", GetLastError());
    #endif // _DEBUG

    closesocket(sock);
    return -2;
}

...
int lookup_host(const wchar_t *host, int family, struct addrinfoW **addrs)
{
    struct addrinfoW hints;
    int errcode;

    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = family;
    hints.ai_socktype = SOCK_STREAM;

    errcode = GetAddrInfoW(host, L"80", &hints, addrs);
    //GetAddrInfoExW(host, L"80", NS_ALL, NULL, &hints, addrs, NULL, NULL, NULL, NULL);
    if (errcode != 0)
    {
        //perror("getaddrinfo");
        return -1;
    }

    return 0;
}

...

struct addrInfoW *res, *addr;

if (lookup_host(host, AF_INET, &res) < 0) { // or AF_INET6, or AF_UNSPEC
    return -1;
}

sock = INVALID_SOCKET;

for(addr = res; addr != NULL; addr = addr->ai_next)
{
    sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
    if (sock == INVALID_SOCKET) {
        break;
    }

    if (connect(sock, addr->ai_addr, addr->ai_addrlen) == 0) {
        break;
    }

    #ifdef _DEBUG
    printf("Error: %d\n", GetLastError());
    #endif // _DEBUG

    closesocket(sock);
    sock = INVALID_SOCKET;
}

FreeAddrInfoW(res);

if (sock == INVALID_SOCKET) {
    return -2;
}

...