Discussion:
Memory Leak in WinHttpSendRequest()
(too old to reply)
prem
2004-01-31 09:06:07 UTC
Permalink
Hello Everybody,

I am developing a HTTP based application in which I am using WinHttp5 extensively. I noticed that machine becomes slow after the program is installed. I tested the program using Rational Purify to check if there are any memory leaks in the program. I tried a small test code ( I have attached the code in this mail ) and tested using Purify. Purify pointed out to the line containing WinHttpSendRequest() for memory leaks. I tried different combinations but still I see purify pointing to that line for memory leaks.

Is there any problem in my piece of code (or) is the winHttp library is responsible for memory leak ?
If WinHttp is the problem point, is there any way to overcome it ?

Thanks in advance.
-Prem


HINTERNET hPeer, hConnect, hReq;
WCHAR wcharHost[MAX_PATH];
DWORD dwError=0;
char sBuffer[MAX_PATH];
DWORD dwBytesRead=0;

DWORD dwFlags = WINHTTP_FLAG_REFRESH | WINHTTP_FLAG_SECURE;
INTERNET_PORT PORT = INTERNET_DEFAULT_HTTPS_PORT;

WCHAR *pszHeader = NULL;
char *pszPostParam = NULL;


wcscpy(wcharHost,L"192.168.1.1");

if ( !(hPeer = WinHttpOpen ( L"test", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, NULL, NULL, 0) ) )
{
return;
}

if (!(hConnect = WinHttpConnect( hPeer,(LPCWSTR)wcharHost,PORT,0)))
{
WinHttpCloseHandle(hPeer);
return;
}

if ( !(hReq = WinHttpOpenRequest (hConnect,L"POST", L"/abc/servletname", NULL, NULL, NULL, dwFlags) ))
{
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hPeer);
return;
}


dwError=0;

pszHeader = new WCHAR[MAX_PATH];
pszPostParam = new char[MAX_PATH];

wcscpy(pszHeader,L"Content-Type: application/x-www-form-urlencoded");
strcpy(pszPostParam, "hostname=192.168.1.1&version=1.0");

if ( !WinHttpSendRequest(hReq, pszHeader, wcslen(pszHeader), (LPVOID)pszPostParam, strlen(pszPostParam),strlen(pszPostParam),0 ))
dwError = GetLastError ();

// End the request.

bRet = WinHttpReceiveResponse( hReq, NULL);

memset(sBuffer, 0, MAX_PATH);
WinHttpReadData(hReq, sBuffer, MAX_PATH*sizeof(char), &dwBytesRead );
sBuffer[dwBytesRead]=0;

WinHttpCloseHandle(hReq);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hPeer);

delete [] pszHeader;
delete [] pszPostParam;
Stephen Sulzer
2004-02-01 00:19:44 UTC
Permalink
Hello,

You don't mention how big the memory leak is, and whether it increases
out-of-control as the program runs. Also, what platform are you running on?

Of course, it is possible that WinHTTP 5.0 has a memory leak. You really
should be using WinHTTP 5.1 where possible. Does the problem repro with
WinHTTP 5.1?

Now, WinHTTP does make some allocations during WinHttpSendRequest that live
beyond the lifetime of the API call, and even past when you close the
corresponding request and session handles. WinHTTP implements a global,
cross-session connection pool. Socket connections, which are created during
WinHttpSendRequest, are kept alive so that they can be reused during other
HTTP requests. This global connection pool will live as long as the WinHTTP
DLL is loaded in the process. If your application is statically linked to
winhttp5.dll, WinHTTP will let the OS handle the cleanup of these resources
when the process terminates. This, however, will look like a leak to
memory-leak detection tools. On the other hand, if the WinHTTP DLL is
dynamically loaded and then unloaded from the process, it will clean up its
global allocations.

So, one thing you can try (although it is a hassle) is to dynamically link
against WinHTTP. This means not linking against winhttp5.lib; instead,
loading WinHTTP5.DLL explicitly using LoadLibrary; using GetProcAddress to
acquire pointers to all the WinHTTP API functions you need; and unloading
the
DLL using FreeLibrary when you are done sending HTTP requests. Dynamically
unloading WinHTTP using FreeLibrary will cause it to deallocate the global
connection pool. I would consider a memory leak bug in WinHTTP to exist only
if the memory leak appears to occur even when the application dynamically
unloads the WinHTTP DLL.

I also note that your test uses SSL. The SSL subsystem on Windows does cache
objects in memory, which may look like a memory leak.

If you are using Windows NT 4.0, you should be aware of some important
post-SP6a updates:

Security Update, July 26, 2001
There are a number of fixes available in the post-SP6a NT4 Security
Update Package. It is recommended that all NT4 machines have this applied:
http://www.microsoft.com/ntserver/nts/downloads/critical/q299444/default.asp

Cache Expiration Does Not Free All Memory Associated with Expired
Credentials
This is a memory leak with the SSL (schannel.dll) subsystem on NT4, fixed in
July 2002:
http://support.microsoft.com/default.aspx?scid=kb;en-us;Q316683

Hope that helps.

Stephen
c***@gmail.com
2016-04-12 18:07:54 UTC
Permalink
Hi,

I believe this WinHttpSendRequest() function is still producing memory leak in Windows 7 (WinHttp 6.1), here what I have:

Platform: Windows 7 Enterprise (version 6.1 SP1) 64 bit platform.
WinHttp: version 6.1.7601.17514.
Visual Studio version: Microsoft Visual Studio Ultimate 2013, Version 12.0.31101.00 Update 4.
Memory leak detect tool: perfmon, using "private bytes".
Symptom: With calling WinHttpSendRequest() memory keep increasing even though it looks like a square, but the trend is going upward. Without calling WinHttpSendRequest, the trend is pretty much flat line even though it looks like a square.

The following is the code,
===================================================
#include "stdafx.h"
#include <stdlib.h>
#include <crtdbg.h>
#include <errno.h>

#include <windows.h>
#include <winhttp.h>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include<cstring>
#include <fstream>
#include <sddl.h>
#include <vector>
#include <Wincrypt.h>
#pragma comment(lib, "winhttp.lib")


UINT32
winhttpGet(HINTERNET Initialize)
{
UINT32 sts = 0;

HINTERNET Connection, File;

Connection = WinHttpConnect(Initialize,
L"www.microsoft.com", //L"www.google.com",
443,
0);
if (!Connection)
{
LPVOID nt_msg;
int err_id = GetLastError();
FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, err_id, 0, (LPTSTR)&nt_msg, 0, NULL);
WinHttpCloseHandle(Initialize);

return(1);
}

File = WinHttpOpenRequest(Connection,
L"GET",
L"en-us/store/gift-cards", //L"?gws_rd=ssl",
L"HTTP/1.1",
WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
WINHTTP_FLAG_SECURE);
if (!File)
{
LPVOID nt_msg;
int err_id = GetLastError();
FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, err_id, 0, (LPTSTR)&nt_msg, 0, NULL);
WinHttpCloseHandle(Initialize);
return(1);
}

if (WinHttpSendRequest(File,
L"Content-Type: application/json\r\nAccept: application/xml",
-1L,
WINHTTP_NO_REQUEST_DATA,
0,
0,
0))
{
std::count << "OK" << std::endl;
}

WinHttpCloseHandle(File);
WinHttpCloseHandle(Connection);

return(sts);
}

int main(int argc, char *argv[])
{

//
// CRT library also indicates WinHttpSendRequest
// is leaking
// 0 bytes in 0 Free Blocks.
// 0 bytes in 0 Normal Blocks.
// 5720 bytes in 5 CRT Blocks. // this is 0 bytes without calling WinHttpSendRequest
// 0 bytes in 0 Ignore Blocks.
// 0 bytes in 0 Client Blocks.
// Largest number used : 4044 bytes.
// Total allocations : 5720 bytes.
// Detected memory leaks!
//
//_CrtMemState s1, s2, s3;
//HANDLE hLogFile;
//hLogFile = CreateFile(L"c:\\log.txt", GENERIC_WRITE,
// FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
// FILE_ATTRIBUTE_NORMAL, NULL);
//_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CRTDBG_CHECK_CRT_DF);
//_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
//_CrtSetReportFile(_CRT_WARN, hLogFile);
//_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
//_CrtSetReportFile(_CRT_ERROR, hLogFile);
//_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
//_CrtSetReportFile(_CRT_ASSERT, hLogFile);
//_CrtMemCheckpoint(&s1);

HINTERNET Initialize = WinHttpOpen(L"HTTPSGET",
WINHTTP_ACCESS_TYPE_NO_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS,
0);
if (Initialize == NULL)
{
LPVOID nt_msg;
int err_id = GetLastError();
FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, err_id, 0, (LPTSTR)&nt_msg, 0, NULL);
WinHttpCloseHandle(Initialize);

return(1);
}

std::cout << "1 round" << std::endl;
std::cin.get();
for (int i = 0; i < 50; i++)
UINT32 sts = winhttpGet(Initialize);
std::cout << "end 1 round" << std::endl;
Sleep(1000 * 40 * 5);

std::cout << "2 round" << std::endl;
for (int i = 0; i < 40; i++)
UINT32 sts = winhttpGet(Initialize);
std::cout << "end 2 round" << std::endl;
Sleep(1000 * 40 * 5);

std::cout << "3 round" << std::endl;
for (int i = 0; i < 60; i++)
UINT32 sts = winhttpGet(Initialize);
std::cout << "end 3 round" << std::endl;
Sleep(1000 * 40 * 5);

std::cout << "4 round" << std::endl;
for (int i = 0; i < 70; i++)
UINT32 sts = winhttpGet(Initialize);
std::cout << "end 4 round" << std::endl;
Sleep(1000 * 40 * 5);

std::cout << "5 round" << std::endl;
for (int i = 0; i < 38; i++)
UINT32 sts = winhttpGet(Initialize);
std::cout << "end 5 round" << std::endl;

std::cout << "6 round" << std::endl;
for (int i = 0; i < 70; i++)
UINT32 sts = winhttpGet(Initialize);
std::cout << "end 6 round" << std::endl;
Sleep(1000 * 40 * 5);

std::cout << "7 round" << std::endl;
for (int i = 0; i < 70; i++)
UINT32 sts = winhttpGet(Initialize);
std::cout << "end 7 round" << std::endl;
Sleep(1000 * 40 * 5);

std::cout << "8 round" << std::endl;
for (int i = 0; i < 70; i++)
UINT32 sts = winhttpGet(Initialize);
std::cout << "end 8 round" << std::endl;
Sleep(1000 * 40 * 5);

WinHttpCloseHandle(Initialize);

std::cin.get();

//_CrtMemCheckpoint(&s2);
//if (_CrtMemDifference(&s3, &s1, &s2))
//{
// _CrtMemDumpStatistics(&s3);
// _CrtDumpMemoryLeaks();
// std::cout << "ERRRRRRRRRRRRRRRRRR" << std::endl;
//}

//CloseHandle(hLogFile);

return 0;
}
===================================================
Post by Stephen Sulzer
Hello,
You don't mention how big the memory leak is, and whether it increases
out-of-control as the program runs. Also, what platform are you running on?
Of course, it is possible that WinHTTP 5.0 has a memory leak. You really
should be using WinHTTP 5.1 where possible. Does the problem repro with
WinHTTP 5.1?
Now, WinHTTP does make some allocations during WinHttpSendRequest that live
beyond the lifetime of the API call, and even past when you close the
corresponding request and session handles. WinHTTP implements a global,
cross-session connection pool. Socket connections, which are created during
WinHttpSendRequest, are kept alive so that they can be reused during other
HTTP requests. This global connection pool will live as long as the WinHTTP
DLL is loaded in the process. If your application is statically linked to
winhttp5.dll, WinHTTP will let the OS handle the cleanup of these resources
when the process terminates. This, however, will look like a leak to
memory-leak detection tools. On the other hand, if the WinHTTP DLL is
dynamically loaded and then unloaded from the process, it will clean up its
global allocations.
So, one thing you can try (although it is a hassle) is to dynamically link
against WinHTTP. This means not linking against winhttp5.lib; instead,
loading WinHTTP5.DLL explicitly using LoadLibrary; using GetProcAddress to
acquire pointers to all the WinHTTP API functions you need; and unloading
the
DLL using FreeLibrary when you are done sending HTTP requests. Dynamically
unloading WinHTTP using FreeLibrary will cause it to deallocate the global
connection pool. I would consider a memory leak bug in WinHTTP to exist only
if the memory leak appears to occur even when the application dynamically
unloads the WinHTTP DLL.
I also note that your test uses SSL. The SSL subsystem on Windows does cache
objects in memory, which may look like a memory leak.
If you are using Windows NT 4.0, you should be aware of some important
Security Update, July 26, 2001
There are a number of fixes available in the post-SP6a NT4 Security
http://www.microsoft.com/ntserver/nts/downloads/critical/q299444/default.asp
Cache Expiration Does Not Free All Memory Associated with Expired
Credentials
This is a memory leak with the SSL (schannel.dll) subsystem on NT4, fixed in
http://support.microsoft.com/default.aspx?scid=kb;en-us;Q316683
Hope that helps.
Stephen
c***@gmail.com
2016-04-14 12:52:54 UTC
Permalink
Looks like no many people look at this group :-)
I re-posted to
https://social.msdn.microsoft.com/Forums/vstudio/en-US/213db7c8-2f95-4286-b1af-6fd238ab819e/memory-leak-in-winhttp-61-routine-winhttpsendrequest-on-windows-7?forum=vsx

and see whether microsoft support has solution.

Loading...