0

当尝试重新分配内存时,我在使用此代码时崩溃:

//value of i is currently 4096
while((c = recv(sock, htmlbff + q, MAXDATASIZE, 0)) > 0)
{
    if((i - q) < MAXDATASIZE)
    {
            i *= 2;
            if(!(tmp = realloc(htmlbff, i)))
            {
                free(htmlbff);
                printf("\nError! Memory allocation failed!");
                return 0x00;
            }
            htmlbff = tmp;
    }
    q += c;
}

它由于内存泄漏而崩溃....但是以下代码不会崩溃:

while((c = recv(sock, htmlbff + q, MAXDATASIZE, 0)) > 0)
{
    if((i - q) < MAXDATASIZE)
    {
        i *= 2;
        if(!(tmp = realloc(htmlbff, i)))
        {
            free(htmlbff);
            printf("\nError! Memory allocation failed!");
            return 0x00;
        }
    }
    htmlbff = tmp;
    q += c;
}

移出htmlbff = tmp;if 语句如何解决这个问题?在 if 语句中似乎没有设置htmlbfftmp...我非常困惑。

4

2 回答 2

3
/*
 * I assume these exist, and more or less fit the requirements described.
 * They don't have to be these specific numbers, but they do need to have
 * the specified relationships in order for the code to work properly.
 */
#define MAXDATASIZE 4096    /* any number here is ok, subject to rules below */
int i = 4096;               // i >= MAXDATASIZE, or the first recv can trigger UB
char *htmlbff = malloc(i);  // ITYK you can't realloc memory that wasn't malloc'd
int q = 0;                  // q <= i-MAXDATASIZE

/* maybe other code */

while((c = recv(sock, htmlbff + q, MAXDATASIZE, 0)) > 0)
{
    /*
     * You've already just read up to MAXDATASIZE bytes.
     * if (i-q) < MAXDATASIZE, then **your buffer is already too small**
     * and that last `recv` may have overrun it.
     */
    if((i - q) < MAXDATASIZE)
    {
        ... reallocate htmlbff ...
    }
    /* Then you bump q...but too late.  lemme explain in a sec */
    q += c;
}

假设您连续两次接收 4096 个字节。会发生什么:

  1. 第一次读取读取 4096 个字节,从htmlbff + 0.
  2. 由于q还是0,i - q== 4096,所以没有分配。
  3. q增加了 4096。
  4. 第二次读取获得 4096 字节,从htmlbff + 4096. 但是等等,因为我们没有在上次迭代中调整它的大小,它htmlbff只有 4096 字节大,并且整个读取都溢出了缓冲区!
  5. 如果幸运的话,溢出会导致段错误并且程序会死掉。如果你不是,那么 CPU 只是士兵,从这里开始的任何行为都是未定义的。在这一点上,甚至诊断进一步的问题也没有什么意义,因为 $DEITY 知道代码刚刚破坏了什么。

试试这个...

while((c = recv(sock, htmlbff + q, MAXDATASIZE, 0)) > 0)
{
    /* **First**, bump `q` past the stuff you just read */
    q += c;

    /*
     * **Now** check the buffer.  If i-q is too small at this point, the buffer is
     * legitimately too small for the next read, and also hasn't been overrun yet.
     */
    if((i - q) < MAXDATASIZE)
    {
        /* This temp pointer **really** should be limited in scope */
        char *double_sized;

        /* Note that otherwise, i'm using the "broken" resize code.
         * It should work fine.
         */
        i *= 2;
        if(!(double_sized = realloc(htmlbff, i)))
        {
            free(htmlbff);
            printf("\nError! Memory allocation failed!");
            return 0x00;
        }
        htmlbff = double_sized;
    }
}
于 2012-08-24T22:20:19.953 回答
1

您不能使用小于数据的缓冲区接收数据,然后重新分配它以适应更大的数据。

你需要重写你的代码:

buffer = malloc(MAXDATASIZE)
size_t received = 0    
while ((size_t sz = recv(sock, buffer+received, MAXDATASIZE-received, 0) > 0)
{
       received += sz 
}
buffer = realloc(buffer, received);

我更改了变量名称,并为澄清而冗长。您的代码的奇怪行为可能是随机的,并且两个代码都是错误的。您可以在这里了解更多信息:http ://en.wikipedia.org/wiki/C_dynamic_memory_allocation

于 2012-08-24T19:55:10.377 回答