/*
* 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 回続けて受信したとします。何が起こるか:
- 最初の読み取りでは、 から始まる 4096 バイトが読み取られ
htmlbff + 0
ます。
q
はまだ 0 なので、 == 4096 なので、i - q
割り当ては行われません。
q
は 4096 に跳ね上がります。
- 2 番目の読み取りは、から始まる 4096 バイトを取得し
htmlbff + 4096
ます。しかし、待ってください。前回の繰り返しでサイズを変更しなかったため、サイズhtmlbff
はわずか 4096 バイトであり、読み取り全体がバッファから溢れ出します!
- 運が良ければ、オーバーランによってセグメンテーション違反が発生し、プログラムが停止します。そうでない場合、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;
}
}