There is a function in my application in which memory is allocated for formatting a port name. CreateFile
is called to open the port. At the end of the function free
is called to attempt to free the allocated memory.
DWORD CSerialPort::Open( wchar_t * port )
{
DCB dcb = {0};
LPTHREAD_START_ROUTINE pThrea开发者_如何学编程dStart;
void * pvThreadData = NULL;
wchar_t * pwcPortName = NULL;
DWORD dwRetVal = ERROR_SUCCESS;
/* Validate parameters. */
pwcPortName = (wchar_t *)malloc( wcslen( port ) + 6 );
if ( pwcPortName == NULL )
{
TRACE(_T("CSerialPort::Open : Failed to allocate memory for formatted serial port name.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), ERROR_NOT_ENOUGH_MEMORY, __WFILE__, __LINE__);
return ERROR_NOT_ENOUGH_MEMORY;
}
memcpy( pwcPortName, L"\\\\.\\", 4 * 2 );
memcpy( pwcPortName + 4, port, wcslen( port ) * 2 + 2 );
// Get a handle to the serial port.
_hSerialPort = CreateFile(
pwcPortName, // Formatted serial port
GENERIC_READ | GENERIC_WRITE, // Access: Read and write
0, // Share: No sharing
NULL, // Security: None
OPEN_EXISTING, // OM port already exists
FILE_FLAG_OVERLAPPED, // Asynchronous I/O
NULL // No template file for COM port
);
if ( _hSerialPort == INVALID_HANDLE_VALUE )
{
TRACE(_T("CSerialPort::Open : Failed to get the handle to the serial port.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), ::GetLastError(), __WFILE__, __LINE__);
return ::GetLastError();
}
/* Initialize the DCB structure with COM port parameters with BuildCommDCB. */
/* Set the serial port communications events mask with SetCommMask. */
/* Set serial port parameters with SetCommState. */
/* Set the serial port communications timeouts with SetCommTimeouts. */
/* Create thread to handle received data with CreateThread. */
free( pwcPortName ); // <-- Exception thrown here.
return dwRetVal;
}
Can anyone tell me what I'm doing wrong? Thanks.
malloc
allocates bytes, but you are using the allocated memory to store wchar_t
.
You have to change the malloc
size parameter to match your existing memcpy
usage:
pwcPortName = (wchar_t *)malloc( wcslen( port ) + 6 );
should be
pwcPortName = (wchar_t *)malloc( (wcslen( port ) + 6) * sizeof(wchar_t));
Easier solution:
DWORD CSerialPort::Open( std::wstring const& port )
{
// ...
std::wstring portname = L"\\\\.\\" + port;
// Get a handle to the serial port.
_hSerialPort = CreateFile(
portname.c_str(), // ...
Don't worry about freeing memory; C++ will now take care of that.
Try:
pwcPortName = (wchar_t *)malloc( sizeof(wchar_t) * (wcslen( port ) + 6) );
...because a wchar_t
is two bytes in a unicode app. You'll have to make a similar change in your second memcpy
call too.
But this being C++, you should use new
and delete
instead:
pwcPortName = new wchar_t[wcslen( port ) + 6];
//...
delete[] pwcPortName;
This would be neater:
DWORD CSerialPort::Open( wchar_t * port )
{
DCB dcb = {0};
LPTHREAD_START_ROUTINE pThreadStart;
void* pvThreadData = NULL;
DWORD dwRetVal = ERROR_SUCCESS;
/* Validate parameters. */
std::wstring pwcPortName;
pwcPortName.append(L"\\\\.\\");
// memcpy( pwcPortName, L"\\\\.\\", 4 * 2 );
// ^^^ Whats this magic number? sizeof(wchar_t)
// ^^^ Is this one the size of the string?
// If you change the string you also need to
// modify the 4? Thats not good (hard to
// maintain (or should I say easy to break))
pwcPortName.append(port);
// memcpy( pwcPortName + 4, port, wcslen( port ) * 2 + 2 );
// ^^^ Magic Number. Are you sure this is even correct?
// Adding 4 to this moves the pointer 4 * sizeof(wchar_t)
// So now you have an implied dependency on the above code
// in this line. So if the string was changed you would need
// to modify the 4 in two places!
// ^^^^^^^ * 2 + 2
// Assume the * 2 is (* sizeof(wchar_t))
// And the + 2 is (+ sizeof(wchar_t)) is to make sure
// you copied the null terminator.
// Get a handle to the serial port.
_hSerialPort = CreateFile(
pwcPortName.c_str(), // Formatted serial port
GENERIC_READ | GENERIC_WRITE, // Access: Read and write
0, // Share: No sharing
NULL, // Security: None
OPEN_EXISTING, // OM port already exists
FILE_FLAG_OVERLAPPED, // Asynchronous I/O
NULL // No template file for COM port
);
// STUFF
// No need to free the pointer as we used a std::Wstring to contain it
// Thus it provides an exception safe memory leak free way of making sure
// the memory is freeed.
return dwRetVal;
}
精彩评论