Re: HeapFree() Failing to deallocate string

Tech-Archive recommends: Repair Windows Errors & Optimize Windows Performance



I've been able to recreate and isolate the problem with HeapFree(),
although I havn't solved it. Attached below is a full and much simpler
program I created to illustrate the problem. The program is essentially
just a "Hello, World!" type program but with eight extra bytes allocated to
the cbWndExtra bytes at window registration in WinMain(). In the first
four bytes I store the number of columns the grid will have (in the real
grid code that is), and in the second four bytes I store a wchar_t** which
in this simplified example is just a pointer to 16 bytes to store pointers
to the four strings, i.e., L"Fred", L"Elsie", L"Mark", and L"Joanne".

The whole program is mostly debug output log code illustrating the
problem very explicitely in that it shows exactly which HeapFree() call is
failing. Attached below is also the output log file created by a run of the
program. Here is the Output Log first:


\\C_DRIVE\Output.txt Opened In WinMain()

Entering WndProc_OnCreate()
iNumColumns=4
hHeap=469958656
pCaps=197168
0 Fred
1 Elsie
2 Mark
3 Joanne
Exiting WndProc_OnCreate(). Bye!!!

Entering WndProc_OnClose()
iColumns=4
0 197184 Fred
1 197216 Elsie
2 197248 Mark
3 197280 Joanne

hHeap=469958656

i ptr+i *(ptr+i) *(ptr+i) HeapFree(hHeap,0,*(ptr+i))
===========================================================================
0 197168 197184 Fred 0 (failure)
1 197172 197216 Elsie 1
2 197176 197248 Mark 1
3 197180 197280 Joanne 1

blnFree=1
\\C_DRIVE\Output.txt Closed In WndProc_OnClose()
Exiting WndProc_OnClose()



Here is the program that creates this output log above:


//This is a whole program and creates a window. Only three messages handled,
//OnCreate(), OnLButtonDown(), and OnClose().
#include <windows.h>
wchar_t *szCaptions[]={L"Fred",L"Elsie",L"Mark",L"Joanne"}; //test strings
HANDLE hFile=0;

typedef struct WndEventArgs //type to pass WndProc() parameters
{
HWND hwnd;
HINSTANCE hInst;
WPARAM wParam;
LPARAM lParam;
}WEA,*lpWEA;

struct EVENTHANDLER // function pointers used call message handlers
{ // I like to modularize my code a lot!
unsigned int Code;
long (*fnPtr)(lpWEA);
}EventHandler[2];

long WndProc_OnCreate(lpWEA wea)
{
unsigned int iNumColumns,i;
static wchar_t szBuffer[256];
HANDLE hHeap;
wchar_t **pCaps;
wchar_t *pStorage;
DWORD cWritten;

wsprintf(szBuffer,L"Entering WndProc_OnCreate()\r\n");
WriteFile(hFile,szBuffer,wcslen(szBuffer)*sizeof(wchar_t),&cWritten,NULL);

//Get Number of Columns.
iNumColumns=sizeof(*szCaptions);
wsprintf(szBuffer,L"iNumColumns=%u\r\n",iNumColumns);
WriteFile(hFile,szBuffer,wcslen(szBuffer)*sizeof(wchar_t),&cWritten,NULL);
SetWindowLong(wea->hwnd,0,iNumColumns);

//Get Memory To Store Names/Captions with HeapAlloc()
hHeap=GetProcessHeap();
wsprintf(szBuffer,L"hHeap=%u\r\n",hHeap);
WriteFile(hFile,szBuffer,wcslen(szBuffer)*sizeof(wchar_t),&cWritten,NULL);
//This memory allocation call will give me sixteen bytes to store four
//wchar_t string pointers

pCaps=(wchar_t**)HeapAlloc(hHeap,HEAP_ZERO_MEMORY,iNumColumns*sizeof(wchar_t));
wsprintf(szBuffer,L"pCaps=%u\r\n",pCaps);
WriteFile(hFile,szBuffer,wcslen(szBuffer)*sizeof(wchar_t),&cWritten,NULL);
SetWindowLong(wea->hwnd,4,(long)pCaps); //store **ptr
for(i=0;i<iNumColumns;i++)
{
//The below calls will give me memory to store the four strings
themselves, and
//of course, the szCaption strings need to be copied to the pointed to
locations.

pStorage=(wchar_t*)HeapAlloc(hHeap,HEAP_ZERO_MEMORY,(wcslen(szCaptions[i])+1)*sizeof(wchar_t));
wcscpy(pStorage,szCaptions[i]);
//Then of course store the string pointers in the sizteen bytes allocated
//for the four pointers.
*(pCaps+i)=pStorage;
wsprintf(szBuffer,L"%u\t%s\r\n",i,szCaptions[i]);
WriteFile(hFile,szBuffer,wcslen(szBuffer)*sizeof(wchar_t),&cWritten,NULL);
}
wsprintf(szBuffer,L"Exiting WndProc_OnCreate(). Bye!!!\r\n\r\n");
WriteFile(hFile,szBuffer,wcslen(szBuffer)*sizeof(wchar_t),&cWritten,NULL);

return 0;
}

long WndProc_OnLButtonDown(lpWEA wea)
{
SendMessage(wea->hwnd,WM_CLOSE,0,0);
return 0;
}

long WndProc_OnClose(lpWEA wea)
{
static wchar_t szBuffer[256];
unsigned int i,iColumns;
DWORD cWritten;
BOOL blnFree=0;
HANDLE hHeap;
wchar_t **ptr;

wsprintf(szBuffer,L"Entering WndProc_OnClose()\r\n");
WriteFile(hFile,szBuffer,wcslen(szBuffer)*sizeof(wchar_t),&cWritten,NULL);
iColumns=GetWindowLong(wea->hwnd,0);
wsprintf(szBuffer,L"iColumns=%u\r\n",iColumns);
WriteFile(hFile,szBuffer,wcslen(szBuffer)*sizeof(wchar_t),&cWritten,NULL);
ptr=(wchar_t**)GetWindowLong(wea->hwnd,4);
for(i=0;i<iColumns;i++)
{
wsprintf(szBuffer,L"%u\t%u\t%s\r\n",i,*(ptr+i),*(ptr+i));
WriteFile(hFile,szBuffer,wcslen(szBuffer)*sizeof(wchar_t),&cWritten,NULL);
}
wsprintf(szBuffer,L"\r\n");
WriteFile(hFile,szBuffer,wcslen(szBuffer)*sizeof(wchar_t),&cWritten,NULL);

hHeap=GetProcessHeap();
wsprintf(szBuffer,L"hHeap=%u\r\n\r\n",hHeap);
WriteFile(hFile,szBuffer,wcslen(szBuffer)*sizeof(wchar_t),&cWritten,NULL);

wsprintf(szBuffer,L"i\tptr+i\t*(ptr+i)\t*(ptr+i)\tHeapFree(hHeap,0,*(ptr+i))\r\n");
WriteFile(hFile,szBuffer,wcslen(szBuffer)*sizeof(wchar_t),&cWritten,NULL);

wsprintf(szBuffer,L"===========================================================================\r\n");
WriteFile(hFile,szBuffer,wcslen(szBuffer)*sizeof(wchar_t),&cWritten,NULL);
for(i=0;i<iColumns;i++)
{
//blnFree=HeapFree(hHeap,0,*(ptr+i));

wsprintf(szBuffer,L"%u\t%u\t%u\t\t%s\t\t%u\r\n",i,ptr+i,*(ptr+i),*(ptr+i),HeapFree(hHeap,0,*(ptr+i)));
WriteFile(hFile,szBuffer,wcslen(szBuffer)*sizeof(wchar_t),&cWritten,NULL);
}
wsprintf(szBuffer,L"\r\n");
WriteFile(hFile,szBuffer,wcslen(szBuffer)*sizeof(wchar_t),&cWritten,NULL);
blnFree=HeapFree(hHeap,0,ptr);
wsprintf(szBuffer,L"blnFree=%u\r\n",blnFree);
WriteFile(hFile,szBuffer,wcslen(szBuffer)*sizeof(wchar_t),&cWritten,NULL);

wsprintf(szBuffer,L"\\\\C_DRIVE\\Output.txt Closed In
WndProc_OnClose()\r\n");
WriteFile(hFile,szBuffer,wcslen(szBuffer)*sizeof(wchar_t),&cWritten,NULL);
wsprintf(szBuffer,L"Exiting WndProc_OnClose()\r\n");
WriteFile(hFile,szBuffer,wcslen(szBuffer)*sizeof(wchar_t),&cWritten,NULL);
CloseHandle(hFile);
PostQuitMessage(0);

return 0;
}

void AttachEventHandlers(void)
{
EventHandler[0].Code=WM_CREATE,
EventHandler[0].fnPtr=WndProc_OnCreate;
EventHandler[1].Code=WM_LBUTTONDOWN,
EventHandler[1].fnPtr=WndProc_OnLButtonDown;
EventHandler[2].Code=WM_CLOSE, EventHandler[2].fnPtr=WndProc_OnClose;
}

LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
unsigned int i;
static WEA Wea;

for(i=0;i<3;i++)
{
if(EventHandler[i].Code==message)
{
Wea.hwnd=hwnd,Wea.lParam=lParam,Wea.wParam=wParam;
return (*EventHandler[i].fnPtr)(&Wea);
}
}

return (DefWindowProc(hwnd,message,wParam,lParam));
}

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR
lpCmdLine,int nCmdShow)
{
wchar_t szName[]=L"Start14";
DWORD cWritten,dwStyle;
wchar_t szBuffer[256];
WNDCLASS wndClass;
HWND hwndMain;
MSG msg;
RECT rc;

AttachEventHandlers();
wndClass.lpszClassName=szName;
//wndClass.style=WS_OVERLAPPED | WS_VISIBLE | WS_SYSMENU;
wndClass.style=0;
wndClass.lpfnWndProc = WndProc;
wndClass.cbClsExtra = 0; wndClass.cbWndExtra = 8;
wndClass.hInstance = hInstance; wndClass.hIcon = NULL;
wndClass.lpszMenuName = NULL; wndClass.hCursor = NULL;
wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
RegisterClass(&wndClass);
SystemParametersInfo(SPI_GETWORKAREA,0,&rc,0);

hFile=CreateFile(L"\\C_DRIVE\\Output.txt",GENERIC_WRITE,0,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
wsprintf(szBuffer,L"\\\\C_DRIVE\\Output.txt Opened In WinMain()\r\n\r\n");
WriteFile(hFile,szBuffer,wcslen(szBuffer)*sizeof(wchar_t),&cWritten,NULL);
dwStyle=WS_OVERLAPPED | WS_VISIBLE | WS_SYSMENU;

hwndMain=CreateWindow(szName,szName,dwStyle,0,0,rc.right,rc.bottom,0,0,hInstance,0);
while(GetMessage(&msg,NULL,0,0)==TRUE)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (msg.wParam);
}

In the WndProc_OnCreate(), after determining that there are four
strings for which storage needs to be allocated, the program uses HeapAlloc()
to get storage for sixteen bytes. Note that pCaps is a wchar_t** and the
allocated storage location is stored in cbWndExtra bytes using
SetWindowLong(). In the above run the number stored was 197168. Directly
after that the four strings are run through a for loop in which HeapAlloc()
is called four more times to get storage owned by the application for the
four strings themselves. Then the four strings are copied to the new
storage. The storage pointers returned are:

0 197184 Fred
1 197216 Elsie
2 197248 Mark
3 197280 Joanne

These pointers are then copied to my allocated storage for them pointed
to by pCaps, i.e., 197168. Then WndProc_OnCreate() returns.

In WndProc_OnClose() I want to clean up. First I retrieve the
information in the cbWndExtra bytes to make sure it got put in correctly in
OnCreate(). Then I print out a nice table showing all the information and
addresses of everything. As you can see, there are the addresses where the
four pointers are stored, i.e., 197168, 197172, 197176, and 197180. The
pointers pointing directly at the strings are in column three, the strings
themselves in column four. Column five shows the results of the HeapFree()
calls on the string pointers executed by way of the
circuitous route of a wsprintf() statement to make nice output:

i ptr+i *(ptr+i) *(ptr+i) HeapFree(hHeap,0,*(ptr+i))
===========================================================================
0 197168 197184 Fred 0
1 197172 197216 Elsie 1
2 197176 197248 Mark 1
3 197180 197280 Joanne 1

And of course, there you can see the failing HeapFree() call for the
string "Fred". HeapFree() returns a BOOL. When 'i' in the loop equals zero
the compiler does not seem to be resolving *(ptr+0) correctly. Do I have a
notation problem here? Perhaps I don't understand pointers? Am confused?
Is there a better notation for doing this sort of operation, perhaps using
typedefs?


"Steve Maillet (eMVP)" wrote:

Where is/was the corresponding HeapAlloc() call performed?

--
Steve Maillet
EmbeddedFusion
www.EmbeddedFusion.com
smaillet at EmbeddedFusion dot com



.



Relevant Pages

  • Re: A taxonomy of types
    ... however, elsewhere in my project (off in the dynamic typesystem, ...), I ... (since I am using NULL-terminated strings), and so I have used U+10FFFF ... remember, C also has things like arrays, funtion pointers, nestable ... int RIL_TypeSmallIntP; ...
    (comp.lang.misc)
  • Re: new IL: C (sort of...).
    ... only for "recent" Pascals, ... far pointers weren't really limited, ... in my compiler, I made wchar_t a builtin type (in most cases, aliased to ... I could very well include builtin "managed strings" in the new IL. ...
    (comp.lang.misc)
  • Re: Increasing efficiency in C
    ... >> The representation of a string in C is the sequence of characters, ... strings, they are passed the addresses of strings. ... supports pointers the way it does. ... Competent programmers make mistakes, too. ...
    (comp.lang.c)
  • Re: K&R2 Secition 5.9 - major blunders
    ... Would changing 'point to a' to 'point into a' twenty element array be ... > arrays of pointers is to store character strings of diverse ... comparison between what was really happening (arrays of pointers to ... pointer to a string(this probably would confuse beginners)" and ...
    (comp.lang.c)