/*
* 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;
}
Let's say you recv 4096 bytes twice in a row. What happens is:
- The first read reads 4096 bytes, starting at
htmlbff + 0
.
- Since
q
is still 0, i - q
== 4096, so no allocation is done.
q
is bumped up by 4096.
- The second read gets 4096 bytes, starting at
htmlbff + 4096
. But wait, since we didn't resize it last iteration, htmlbff
is only 4096 bytes big, and the entire read spills out of the buffer!
- If you're lucky, the overrun causes a segfault and the program dies. If you're not, then the CPU just soldiers on, and any behavior from here on is undefined. There's very little point in even diagnosing further issues at this point, since $DEITY knows what the code just trashed.
Try this instead...
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;
}
}