Crash with overlapped RS232 communication

Hi everyone,

I have a quite misterous problem. I am developing a windows application which is using the serial port for data transfere. I have developed a serial class based on the MSDN article Serial Communications in Win32. My application uses asnychron communication with overlapped structure.

The communication at the first sight is OK. But if there are more copies of my applications running on the same PC using DIFFERNET serial ports, after few day of running and receiving datas suddenly appears the following messagebox by each one of the application at the same time:

Runtime Error! Program: myapp.exe This application has requested the Runtime to terminate it in an unusual way.

Each one of the applications stops receiving datas through the serial port, but their GUI is still active. As soon as I press the OK button on the dialog, each application closes.

I have succeed to figure out, that there is some kind of memory leak. The memory grows slowly and when it comes to certain point the Runtime error messagebox appears. While the messagebox is on the command returns with error and the overlapped event is not created!

OVERLAPPED osReader = {0};
osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

I guess I have to have some problem in the receiving routine. I went through my code several times but I couldn't find the error. There are 3 threads running 1 for the GUI, 1 for the serial data receiving and 1 for the serial data processing. The data are transfered between threads with deques.

What is very strange this error only happens if more than 1 of my applications are running. By 1 application everything is OK and the memory also stays at the same level.

Here is the receiving routine:

int UModulSerial::ReceiveVoid(LPVOID Buffer, int &NumberOfBytesToRead)
{

//overlapped read, it's possible, that we have to wait with waitforsingle object till the read operation finishes
if (m_bOverlapped)
{
CMutex mutRead;
CSingleLock lock(&mutRead,TRUE); //this will block other processes to read from the com port till our operation finishes
m_sError = "";
m_iErrNumber = 0;
DWORD NumberOfBytesReceived=0;

OVERLAPPED osReader = {0};
osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (osReader.hEvent == NULL)
{
SetErrorMessage(ERROR_CREATING_EVENT);
return -1;
}

int Read_Error = ReadFile
(
m_hSerPort, // handle of file to read
Buffer, // pointer to buffer that receives data
NumberOfBytesToRead, // number of bytes to read
&NumberOfBytesReceived, // pointer to number of bytes read
&osReader // pointer to OVERLAPPED structure for data
);

if (!Read_Error)
{
DWORD LastErrorCode = GetLastError();
if (LastErrorCode == ERROR_IO_PENDING) //if the read is not yet finished, wait till it finishes, or timeouts
{
DWORD dwRes = WaitForSingleObject(osReader.hEvent, m_Comtimeout.ReadTotalTimeoutConstant);
switch(dwRes)
{
case WAIT_OBJECT_0: // Read completed, transfer the overlapped result to our buffer.
if (!GetOverlappedResult(m_hSerPort, &osReader, &NumberOfBytesReceived, FALSE))
{
//if there was an error during transfering the overlapped structure to our buffer
SetErrorMessage(GetLastError());
CloseHandle(osReader.hEvent);
return -1;
}
else
{
//when the transfer was succesful, but the number of read bytes are not equal to requested than error
if(NumberOfBytesToRead != NumberOfBytesReceived)
{
NumberOfBytesToRead = NumberOfBytesReceived;
SetErrorMessage(ERROR_TIMEOUT);
CloseHandle(osReader.hEvent);
return -1;
}
}
break;
case WAIT_TIMEOUT:
//if there was a timeout during the read operation, than cancel the reading and return with error
SetErrorMessage(ERROR_TIMEOUT);
CancelIo(m_hSerPort);
//we call this to get how many bytes were read till the timeout
GetOverlappedResult(m_hSerPort, &osReader, &NumberOfBytesReceived, FALSE);
//maybe it was timeout but we received all the bytes we requested, in such case everything is ok
if (NumberOfBytesToRead != NumberOfBytesReceived)
{
CloseHandle(osReader.hEvent);
NumberOfBytesToRead = NumberOfBytesReceived;
return -1;
}
else
break;
break;
default:
//this indicates, that there is a problem with the overlapped eventhandler
SetErrorMessage(-1);
CloseHandle(osReader.hEvent);
return -1;
break;
}
}
else
{
// Error in communications; report it.
SetErrorMessage(GetLastError());
CloseHandle(osReader.hEvent);
return -1;
}

}

CloseHandle(osReader.hEvent);
if(NumberOfBytesToRead != NumberOfBytesReceived)
{
NumberOfBytesToRead = NumberOfBytesReceived;
SetErrorMessage(ERROR_TIMEOUT);
return -1;
}

return 0; //we return here, so the lock object will be destroyed in correct moment, when lock destroyed, it calls unlock
}

The receiving is triggered by WaitEventChar function.

Any help or comments are highly appriciated.
Greetings

Attila
[5700 byte] By [battika] at [2007-11-19 19:59:52]
# 1 Re: Crash with overlapped RS232 communication
I'm having some doubts about these lines:

CMutex mutRead;
CSingleLock lock(&mutRead,TRUE); //this will block other processes to read from the com port till our operation finishes

You're using an unnamed mutex here and that won't block other processes. Infact, since you using a local mutex object it won't even block other threads within the same process.

- petter
wildfrog at 2007-11-9 13:20:33 >
# 2 Re: Crash with overlapped RS232 communication
Thanx wildfrog, I think I am completly blind that I haven't noticed this mistake. I corrected this it now I will have to test it.
And that takes a while, because it takes aprox. at least 3 days to make the program crash.

Still would this explain the memory growth?
And why would the program crash only when there are more copies running of it? I access this function only with one thread so there should not be any problem with threads accessing the same resource.
battika at 2007-11-9 13:21:31 >
# 3 Re: Crash with overlapped RS232 communication
I have finaly (after blood sweating) found the problem. There was a Handler overflow, that's why my program crashed.

The problems was with the CreateEvent(NULL, TRUE, FALSE, NULL) for the overlapped structure.

Each time I was calling the receiving function I wasa allocating a handler for the Overlapped hevent:

OVERLAPPED osReader = {0};
osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

Each time I created an event for the ovrelapped.hevent structure the handle was allocated but not deallocated. Don't ask me why. I was correctly using the CloseHandle function to the handle but it didn't work (maybe I have an additional bug in my code).

So my (ugly) solution is that I allocate the handle osReader as a member variable of my Serial class, create it in only once in the constructor and now it seems to work.
battika at 2007-11-9 13:22:30 >
# 4 Re: Crash with overlapped RS232 communication
Utilities such as Performance Monitor (perfmon.exe) are of great value when debugging applications. By attaching it to your application you could monitor the number of handles, memory usage etc. And if the handle count just keept on increasing you would know you got a resource leak.

- petter
wildfrog at 2007-11-9 13:23:32 >