2010-12-01 53 views
1

我的应用程序中有一个函数,其中分配内存以格式化端口名称。调用CreateFile来打开端口。调用free函数结束时会尝试释放分配的内存。免费分配内存产生异常 - C++

DWORD CSerialPort::Open(wchar_t * port) 
{ 
    DCB dcb = {0}; 
    LPTHREAD_START_ROUTINE pThreadStart; 
    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; 
} 

有谁能告诉我我做错了什么吗?谢谢。

+0

您对大小许多假设。通过适当地使用sizeof(wchar_t)来明确这些。也动态分配内存不是异常安全的查找RAII(在这种情况下也称为std :: vector/std :: wstring)。 – 2010-12-01 19:20:22

回答

7

malloc分配字节,但您使用分配的内存来存储wchar_t

你必须改变malloc尺寸参数,以配合您现有memcpy用法:

pwcPortName = (wchar_t *)malloc(wcslen(port) + 6); 

应该

pwcPortName = (wchar_t *)malloc((wcslen(port) + 6) * sizeof(wchar_t)); 
+0

我会使用std :: wstring来保存一个字符串! – 2010-12-01 19:36:22

+0

@Martin - 是的,RAII更可取。如果OP重定向答复接受,我不会抱怨。 – 2010-12-01 19:41:02

3

尝试:

pwcPortName = (wchar_t *)malloc(sizeof(wchar_t) * (wcslen(port) + 6)); 

...因为wchar_t在unicode应用程序中是两个字节。您也必须在第二个memcpy调用中进行类似的更改。

但这是C++,你应该使用newdelete代替:

pwcPortName = new wchar_t[wcslen(port) + 6]; 

//... 

delete[] pwcPortName; 
+1

`wchar_t`不是2个字节。它至少有两个字节,在Windows平台上是两个字节,但并不是无处不在(例如,在POSIX盒子上通常是4个字节)哦,如果是C++,他不应该使用`new`和`delete` ;他应该使用`vector`;) – 2010-12-01 15:51:45

+1

考虑到它是`CreateFileW`的一个参数,我相信可以安全地认为这是Windows而不是POSIX。编写便携式非可移植代码确实没有意义。 – MSalters 2010-12-01 16:06:51

4

简单的解决方案:

DWORD CSerialPort::Open(std::wstring const& port) 
{ 
    // ... 
    std::wstring portname = L"\\\\.\\" + port; 

    // Get a handle to the serial port. 
    _hSerialPort = CreateFile(
     portname.c_str(), // ... 

不要担心释放内存;现在C++会照顾到这一点。

1

这将是整洁:

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; 
}