I decided it was time to get my hands dirty, so I installed Visual Studio and started digging. I'm not a coder by trade, so there may be better ways to address these leaks.
1. Mr. Colby Dillion was correct, in that there are a number of handles which need to be closed in the area he describes. I was seeing a leak of 4handles/association, and here's what I changed to fix that:
PS - From what I gather using google, the closesocket() calls can cause trouble with Windows 95 if the child isn't done using the socket yet. Unfortunatly using CloseHandle() on the accept socket handles resulted in odd behavior and continued handle leaking.
dul.cxx ~line 1700 before:
Code: Select all
// PROCESS_INFORMATION pi now contains various handles for the new process.
// Now that we have a handle to the new process, we can duplicate the
// socket handle into the new child process.
if (DuplicateHandle(GetCurrentProcess(), (HANDLE)sock, pi.hProcess,
&childSocketHandle, 0, TRUE, DUPLICATE_CLOSE_SOURCE))
{
// close handles in PROCESS_INFORMATION structure
// and our local copy of the socket handle.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
CloseHandle((HANDLE)sock);
// send number of socket handle in child process over anonymous pipe
DWORD bytesWritten;
char buf5[20];
sprintf(buf5,"%i",(int)childSocketHandle);
if (!WriteFile(hChildStdInWriteDup, buf5, strlen(buf5)+1, &bytesWritten, NULL))
{
CloseHandle(hChildStdInWriteDup);
return makeDcmnetCondition (DULC_CANNOTFORK, OF_error, "error while writing to anonymous pipe");
}
// return OF_ok status code DULC_FORKEDCHILD with descriptive text
char buf4[256];
sprintf(buf4, "new child process started with pid %i, socketHandle %i",
OFstatic_cast(int, pi.dwProcessId),
(int)childSocketHandle);
return makeDcmnetCondition (DULC_FORKEDCHILD, OF_ok, buf4);
}
else
{
// unable to duplicate handle. Close handles nevertheless
// to avoid resource leak.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
CloseHandle((HANDLE)sock);
return makeDcmnetCondition (DULC_CANNOTFORK, OF_error, "error while duplicating socket handle");
}
dul.cxx ~line 1700 after:
Code: Select all
// PROCESS_INFORMATION pi now contains various handles for the new process.
// Now that we have a handle to the new process, we can duplicate the
// socket handle into the new child process.
HANDLE ParentProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId()); // (Colby Dillon) fix for Win2k support
if (DuplicateHandle(ParentProcessHandle, (HANDLE)sock, pi.hProcess,
&childSocketHandle, 0, TRUE, DUPLICATE_SAME_ACCESS)) // (Colby Dillon) fix for Win2k support
{
// close handles in PROCESS_INFORMATION structure
// and our local copy of the socket handle.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
CloseHandle(ParentProcessHandle); // (Colby Dillon) fix for Win2k support
closesocket((SOCKET)sock); // (rhinojunk) fixes handle leak
// send number of socket handle in child process over anonymous pipe
DWORD bytesWritten;
char buf5[20];
sprintf(buf5,"%i",(int)childSocketHandle);
if (!WriteFile(hChildStdInWriteDup, buf5, strlen(buf5)+1, &bytesWritten, NULL))
{
CloseHandle(hChildStdInWriteDup);
CloseHandle(hChildStdInRead); // (rhinojunk) fixes handle leak
closesocket((SOCKET)childSocketHandle); // (rhinojunk) fixes handle leak
return makeDcmnetCondition (DULC_CANNOTFORK, OF_error, "error while writing to anonymous pipe");
}
CloseHandle(hChildStdInWriteDup); // (rhinojunk) fixes handle leak
CloseHandle(hChildStdInRead); // (rhinojunk) fixes handle leak
// return OF_ok status code DULC_FORKEDCHILD with descriptive text
char buf4[256];
sprintf(buf4, "new child process started with pid %i, socketHandle %i",
OFstatic_cast(int, pi.dwProcessId),
(int)childSocketHandle);
closesocket((SOCKET)childSocketHandle); // (rhinojunk) fixes handle leak
return makeDcmnetCondition (DULC_FORKEDCHILD, OF_ok, buf4);
}
else
{
// unable to duplicate handle. Close handles nevertheless
// to avoid resource leak.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
CloseHandle(ParentProcessHandle); // (Colby Dillon) fix for Win2k support
closesocket((SOCKET)sock); // (rhinojunk) fixes handle leak
CloseHandle(hChildStdInWriteDup); // (rhinojunk) fixes handle leak
CloseHandle(hChildStdInRead); // (rhinojunk) fixes handle leak
return makeDcmnetCondition (DULC_CANNOTFORK, OF_error, "error while duplicating socket handle");
}
2. Most of the memory leak appears to be caused when the DUL_ReceiveAssociationRQ function calls createAssociationKey creating a PRIVATE_ASSOCIATIONKEY structure which never gets released. My fix is as follows:
dul.cxx ~line 597 before:
Code: Select all
cond = receiveTransportConnection(network, block, timeout, params, association);
if (cond.bad() || (cond.code() == DULC_FORKEDCHILD))
return cond;
dul.cxx ~line 597 after:
Code: Select all
cond = receiveTransportConnection(network, block, timeout, params, association);
if (cond.bad() || (cond.code() == DULC_FORKEDCHILD))
{
destroyAssociationKey(association); // (rhinojunk) otherwise association leaks ~17KB/association
return cond;
}
The result is that I'm seeing a leak of only about 0.6KB/association instead of 18KB/association.