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ステートメントの外に移動することでこの問題をどのように修正できますか?htmlbffifステートメントの中には設定されていないようですtmp...私は非常に混乱しています。

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 バイトを 2 回続けて受信したとします。何が起こるか:

  1. 最初の読み取りでは、 から始まる 4096 バイトが読み取られhtmlbff + 0ます。
  2. qはまだ 0 なので、 == 4096 なので、i - q割り当ては行われません。
  3. qは 4096 に跳ね上がります。
  4. 2 番目の読み取りは、から始まる 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 に答える