Вы не инициализируете temp
, и, кроме того, ваш звонок на realloc
неправильный. Должно быть:
temp = realloc (temp, recvsize+1);
Когда вы звоните realloc
, как вы, вы выбрасываете новый адрес, и есть большая вероятность, что старый адрес теперь освобожден. Все ставки отменяются, когда вы пытаетесь разыменовать его.
Причина, по которой realloc
возвращает новый адрес, заключается в том, что расширение буфера может потребовать его перемещения, если этот текущий блок окружен областью памяти (другими словами, он не может просто развернуться в свободный блок после него ). В этом случае на арене будет создан новый блок, содержимое которого будет перенесено из старого блока, а старый блок будет освобожден. Вы должны получить возвращаемое значение от realloc
в случае, если это произойдет.
Имейте в виду, что realloc
не имеет для возврата нового указателя, он может дать вам такой же указатель, если, например, после блока было достаточно свободного места, чтобы удовлетворить новый размер или, если вы уменьшаете размер.
Он также может возвращать NULL, если не может расширить блок, вы должны также следить за этим, особенно если:
temp = realloc (temp, newsize);
приведет к утечке памяти при возврате NULL (это не освобождает старый блок).
Несколько других вещей:
- вам редко нужно использовать
calloc
, особенно в этом случае, так как вы все равно копируете память.
- аналогично, вам не нужно
memset
порция памяти равной 0, если вы сразу же наберете memcpy
поверх него.
- при условии, что вы инициализировали
temp
до NULL
, вы можете просто использовать realloc
без его тестирования. Это потому, что realloc(NULL,7)
идентичен malloc(7)
- realloc
вполне может начинаться с нулевого указателя.
- , поскольку вам не нужно
calloc
, это только для образования - sizeof(char)
это всегда 1 по определению.
- Вы, кажется, делаете огромное количество ненужного копирования данных.
Почему бы нам не начать с чего-то более простого? Теперь, это полностью из моей головы, так что могут быть некоторые ошибки, но это, по крайней мере, отрезано от бегущего в памяти бегемота в вопросе :-), поэтому должно быть легче отлаживать.
Это в основном разбито на:
- инициализировать пустое сообщение.
- войти в бесконечный цикл.
- получить сегмент.
- если произошла ошибка, освободить все и вернуть ошибку.
- если сегментов больше нет, вернуть текущее сообщение.
- создать место для нового сегмента в конце сообщения.
- если пространство не может быть создано, освободите все и верните пустое сообщение.
- добавить сегмент к сообщению и настроить размер сообщения.
и код выглядит так:
int Socket::Recv(char *&vpszRecvd) {
int recvsize = 0;
char TempBuf[1024];
int Result = 0;
char *oldPtr;
// Optional free current and initialise to empty.
//if (vpszRecvd != NULL) free (vpszRecvd);
vpszRecvd = NULL;
// Loop forever (return inside loop on end or error).
do {
Result = recv( this->sSocket, TempBuf, sizeof(TempBuf) -1, 0 );
// Free memory, close socket on error.
if (Result < 0) {
free (vpszRecvd);
closesocket(this->sSocket);
this->sSocket = INVALID_SOCKET;
return SOCKET_ERROR;
}
// Just return data and length on end.
if (Result == 0) {
return recvsize;
}
// Have new data, use realloc to expand, even for initial malloc.
oldPtr = vpszRecvd;
vpszRecvd = realloc (vpszRecvd, recvsize + Result);
// Check for out-of-memory, free memory and return 0 bytes.
if (vpszRecvd == NULL) {
free (oldPtr);
return 0;
}
// Append it now that it's big enough and adjust the size.
memcpy (&(vpszRecvd[recvsize], TempBuf, Result);
recvsize += Result;
} while (1);
}