2015-08-31 7 views
2

У меня есть простая функция, которая позволяет мне получать содержимое файла на сервере. Он работает так, как я хочу , но«Визуальный детектор утечки» указывает на утечку памяти на линии closeSocket(...).Утечка памяти - сокет или строчка?

код ниже:

string executeUrl(const char *url) 
{ 
    SOCKET sConnection; 
    char szHeader[500]; 

    sprintf(szHeader, "GET %s HTTP/1.0\r\n" 
    "Host: %s\r\n" 
    "User-Agent: Agent\r\n" 
    "\r\n", url, HTTPSERVER); 

    sConnection = HTTPConnectToServer(HTTPSERVER); 
    if (sConnection == 0) 
    { 
     return ""; 
    } 
    send(sConnection, szHeader, strlen(szHeader), 0); 
    char reply[1024]; 
    ZeroMemory(reply, 1024); 
    if (recv(sConnection, reply, 1024, 0) == SOCKET_ERROR) 
    { 
     return ""; 
    } 
    string returnString(reply); 
    closesocket(sConnection); 
    WSACleanup(); 
    return returnString; 
} 

Данные просочилась является строка returnString. Так что это либо связанная строка, либо что-то с closesocket().

Я сделал некоторое чтение, и я не могу понять это. По-видимому, струны должны заботиться о себе и не вызывать утечки памяти, не так ли?


EDIT:

Я попытался следующий код: http://www.zedwood.com/article/cpp-winsock-basic-http-connection

Даже этот код создает утечку памяти для меня. Я также тестировал другое приложение (Deleaker), и он также сказал мне, что есть те же утечки памяти.


EDIT2:

Только что узнал его не единственный раз, когда строка утечки памяти. Этот фрагмент кода также является проблемой:

urlString = (string)"http://someurl" + std::wstring_convert<std::codecvt_utf8<wchar_t>>().to_bytes(pcName) + (string)"somefile.php"; 

Проникшие данные - это то, что удерживает «urlString». Я полностью смущен.

+0

Действительно, строка не должна течь. Таким образом, мои деньги находятся на закрытии или в детекторе утечки. – Borgleader

+0

И все же блок «данных» в VLD содержит ТОЧНО, что находится в «returnString». Я убедился, изменив его из «ответа». – GrubyStack

+0

попытался «ИЗМЕНИТЬ», с Visual Studio Express 2013 и Visual Leak Detector 2.3, «Не обнаружено утечек памяти». , Попробовал эту [link] (https://msdn.microsoft.com/en-us/library/windows/desktop/ms740121 (v = vs.85) .aspx) с небольшой модификацией для создания строки на основе полученного буфера - «Нет обнаружены утечки памяти ". – StahlRat

ответ

1

Этот код содержит потенциальную переполнение буфера, вы должны использовать строку конструктор:

string returnString(reply, 1024); 

Конструктор вы используете предполагает, что это передается оканчивающихся нулем строку, которая не может быть в случае в зависимости от результаты recv().

Редактировать: Что такое возвращаемое значение closesocket? Вы уверены, что сокет фактически закрыт до завершения вашей программы? Что произойдет, если вы подождете несколько секунд между вызовом closesocket и прекратите свою функцию?

+0

Не исправляет проблему утечки памяти. – GrubyStack

2

Я ожидал бы некоторого неопределенного поведения. Вы ответили 1024 символа. Затем вы используете конструктор, который ожидает символьную последовательность с нулевым символом. Как вы можете быть уверены, что ответ - последовательность символов с нулевым символом?

Как быстро тест попытаться прочитать 1023 символов вместо 1024, здесь:

if (recv(sConnection, reply, 1023, 0) == SOCKET_ERROR) 
+0

Пробовал, тот же утечка памяти. – GrubyStack

0

все возможное, чтобы следовать некоторые примеры кода из MSDN, т.е. .:

https://msdn.microsoft.com/pl-pl/library/windows/desktop/ms737591(v=vs.85).aspx

или в в наименьшей степени попробуйте запустить этот образец, чтобы проверить, также ли он создает утечки для вас.

Я вижу, вам не хватает shutdown вызова, может ли это привести к утечкам - я не уверен, с его документа вы можете прочитать:

Чтобы гарантировать, что все данные передаются и принимаются на подключенный сокет перед тем он закрыт, приложение должно использовать shutdown для закрытия соединения перед вызовом closesocket.

кстати. при использовании Win API всегда проверяйте все коды ошибок, которые могут быть возвращены из функций api.

+0

Пробовал добавлять выключение, но ничего не меняет. Некоторое время пытаюсь использовать пример msdn. – GrubyStack

2

Когда вы читаете сокет, вы не должны предполагать, что вы получили все свои данные за один раз.

В этом случае сервер мог отправить более 1024 байта, и вы точно прочитали 1024. Что может случиться здесь, так это то, что ваш буфер не будет завершен с NULL и вы попытаетесь инициализировать строку с ним и не дадите ему надлежащей длины. Afaik это неопределенное поведение, так что это первое, что вы можете исправить. Кроме того, вы должны прочитать все данные, отправленные сервером.

char reply[1025]; 
ZeroMemory(reply, 1025); 
string returnString; 
int val = 0; 
do 
{ 
    val = recv(sConnection, reply, 1024, 0); 
    if (val == SOCKET_ERROR) 
    { 
     // Treat errors 
    } 
    strcat (returnString, reply); 
    ZeroMemory(reply, 1025); 
} 
while (val == 1024); 

Edit: Этот код является неправильным. Без предварительного обмена сообщениями с сервером, действительно сложно определить, сколько байтов или какое содержимое должно иметь сообщение. В случае этого кода, если сервер отправляет ровно 1024 байта, то recv будет заблокирован на следующей итерации, потому что читать нечего. Сетевые протоколы устанавливают эти основные правила связи. Например, протокол http утверждает, что первая часть сообщения состоит из заголовков, каждый заголовок заканчивается парой CRLF, а конец заголовка помечен двумя парами CRLF. Чтобы мой код был правильным, мне пришлось бы разбирать заголовки и извлекать значение Content-Length, а затем читать тело сообщения до тех пор, пока я не дойду до указанной длины.

+0

Что делать, если я не забочусь ни о чем после первых 1024 байтов? Могу ли я прочитать первые 1024 байта и вернуть то, что было получено в виде строки без утечки памяти? – GrubyStack