【问题标题】:C CrtIsValidHeapPointer ErrorC CrtIsValidHeapPointer 错误
【发布时间】:2014-04-06 07:07:26
【问题描述】:

我正在开发一个 C 代码来执行 GET 请求并处理可​​变大小的响应。

我使用 realloc 来调整我存储响应的堆块的大小。问题是我收到了与 realloc 调用的 CrtIsValidHeapPointer 函数相关的错误。

循环运行了 6 次,但在第 7 次循环时出现错误。 我这里有你的代码:

#include "stdafx.h"

using namespace std;
int GET_request(char *hostname, char *path);
char *scat(char *, char *);
int _tmain(int argc, _TCHAR* argv[])
{
    GET_request("www.marca.com", "/");
}

int GET_request(char *hostname, char *path){

char request[256];
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
    printf("WSAStartup failed.\n");
    system("pause");
    return 1;
}
SOCKET Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct hostent *host;
host = gethostbyname(hostname);
SOCKADDR_IN SockAddr;
SockAddr.sin_port = htons(80);
SockAddr.sin_family = AF_INET;
SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr);
printf("Connecting...\n");
if (connect(Socket, (SOCKADDR*)(&SockAddr), sizeof(SockAddr)) != 0){
    printf("Could not connect");
    system("pause");
    return 1;
}
printf("Connected.\n");

if ((strlen(hostname) + strlen(path)) > 197)
{
    printf("Lenght too long for a GET path");
    return 1;
}
else
{
    const char *method = "GET ";
    strcpy_s(request, method);
    strcat_s(request, path);
    strcat_s(request, " HTTP/1.1\r\n");
    strcat_s(request, "Host: ");
    strcat_s(request, hostname);
    strcat_s(request, "\r\n");
    strcat_s(request, "Connection: close\r\n\r\n");
}

//printf_s(request);

int len;
len = strlen(request);
system("pause");
send(Socket, request, strlen(request), 0);
char *ptr = (char*)calloc(sizeof(char),1024);
char *ptr2 = NULL;
int nDataLength;
int i = 0;
while ((nDataLength = recv(Socket, ptr, 1023, 0)) > 0){

    if (i > 0){//prepare in case that the response is bigger than 1024 bytes
        //printf("Data len: %d\n", nDataLength);    
        //system("pause");
        printf("%p apunta a %d len: %d e i vale: %d\n", ptr2, *ptr2, ((1023 * i) + nDataLength), i);
        system("pause");
        ptr2 = (char*)realloc(ptr2, ((1023 * i) + nDataLength));
        if (ptr2==NULL){
            printf("Some error reallocating memory\n");
            system("pause");
            i++;
        }
        else{
            memcpy(ptr2 + (1024 * i), ptr, nDataLength);
            //printf("%s\n", ptr2);
            //system("pause");
            i++;
        }

    }
    else{
        ptr2 = (char*)realloc(ptr2, ((1023 * i) + nDataLength));
        memcpy(ptr2, ptr, nDataLength);
        i++;
    }
}
printf("%s",ptr2);
system("pause");

closesocket(Socket);
WSACleanup();
system("pause");
FILE* pFile;
pFile = fopen("myfile.txt", "wb");
fwrite(ptr2, 1, strlen(ptr2), pFile);
fclose(pFile);
free(ptr2);
return 0;
}

您可以检查while 循环。我只是想给你所有的代码,以防你想尝试它。 我得到了这个:

Connecting... Connected. Press any key to continue . . . 0033D500 apunta a 72 len: 2046 e i vale: 1 Press any key to continue . . . 0033D500 apunta a 72 len: 3069 e i vale: 2 Press any key to continue . . . 0033D500 apunta a 72 len: 4092 e i vale: 3 Press any key to continue . . . 0033D500 apunta a 72 len: 5115 e i vale: 4 Press any key to continue . . . 0033D500 apunta a 72 len: 6138 e i vale: 5 Press any key to continue . . . 0033D500 apunta a 72 len: 7161 e i vale: 6 Press any key to continue . . .

谢谢

【问题讨论】:

  • 您无需读取套接字即可测试该 realloc 循环。只需从文件中提取数据。而且您的指针数学似乎不正确,至少在其他条件下。您正在读取 1023 字节的块,始终将最后一个插槽保存为终结符,但其他插槽从 (i*1024) 开始。每次迭代时,您都会将i 插槽移出分配范围并移至 UB。最后,这与 C++ at all 有什么关系?如果您使用 C++,请使用向量并将所有这些 realloc 垃圾扔掉;否则会丢失 C++ 标签。

标签: c memory-management malloc realloc


【解决方案1】:

你正在分配

ptr2 = (char*)realloc(ptr2, ((1023 * i) + nDataLength));

使用1023*i,但在复制中

memcpy(ptr2 + (1024 * i), ptr, nDataLength);

即使用1024*i

所以你写的比你分配的要多。引用未分配的内存是未定义的行为,很可能在某些时候导致致命错误。

【讨论】:

  • 多么愚蠢的错误!!!对不起。我之前使用 1024 作为长度,我没有在另一个 memcpy 中更改它。无论如何,我希望我的代码可以帮助其他人为变量响应分配内存。顺便说一句,如果我们不知道响应的长度,这是处理套接字响应的最佳方式吗?谢谢
  • 你知道我为什么要在 ptr2 中添加一些多余的字符吗?这是 C 代码:pastebin.com/ZFX3A3X5 这是我保存在文件中的内容(假设响应):pastebin.com/hpjuYaeu 为什么我有“389”、“200”、“385”、“0”和“ýýýý«« ««««««þîþîþ" ????你能看一下吗?
  • @Alberto,我不确定,但这是有效数据吗?您正在将二进制数据写入文件?在这种情况下,并非所有字符都是可见的 ascii。
  • 不是。我的意思是套接字的响应不包含这些值。我正在使用网络代理来检查它,肯定还有别的东西。每次执行 memcpy 时,是否需要将 ptr2 的最后一个字符设置为“\0”?谢谢
  • @Alberto,是的,在ptr2 末尾的每个循环中设置'\0',因为您稍后将其用作字符串。
猜你喜欢
  • 1970-01-01
  • 2017-08-01
  • 2014-04-28
  • 1970-01-01
  • 1970-01-01
  • 2012-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多