My application has some debug code written specifically to send debug data to the Output Window when running in debug mode. When the function GetCurrTime is called in the below code snippet the application crashes on the following call to malloc when I step through the code, or on the line preceding the call to malloc, if I let it free-run. However, the real oddity here is that when the crash occurs, the PC does not land on either of these lines. The PC stops on the return line in an entirely unrelated function. It gets better. The Call Stack shows no place for the function to return to. I’m guessing that somehow the PC is getting off into the weeds. What makes this all really odd, is that when I comment out the call to GetCurrTime the problem goes away.
void PrintDevMsgTrace( LPBYTE pMsg, PWCHAR fnName )
{
#ifdef _DEBUG
BYTE byMsgLen;
TCHAR * ptTimeStr = NULL;
WORD cmd;
int i, j = 0;
int iTimeStrLen, iStrLen, iPreOffset, iPostOffset;
wchar_t * pCmdIdStr = NULL;
wchar_t * pBuf = NULL;
byMsgLen = pMsg[DEV_LEN_OFFSET] + sizeof(devPktHead_t) + sizeof(devPktTail_t);
cmd = pMsg[DEV_CMD_MSB_OFFSET];
cmd <<= 8;
cmd |= pMsg[DEV_CMD_LSB_OFFSET];
pCmdIdStr = GetCmdIdStr( cmd );
ptTimeStr = GetCurrTime();
iTimeStrLen = ::wcsnlen_s( ptTimeStr, 128 );
iPreOffset =
iTimeStrLen // time string
+ 1 // "-"
+ ::wcsnlen_s( fnName, 128 ) // function name
+ 3 // " : "
+ ::wcsnlen_s( pCmdIdStr, 128 ) // command ID string
+ 3; // " 0x"
iPostOffset = iPreOffset + byMsgLen * 3; // "%.2X " (formatted: 2 hex-nibble bytes and space)
iStrLen = iPostOffset + 3; // "\r\n\0"
pBuf = (wchar_t *)::malloc( iStrLen * sizeof(wchar_t) );
::swprintf_s( pBuf, iStrLen, _T("%s-%s : %s 0x"), ptTimeStr, fnName, pCmdIdStr);
for ( i = iPreOffset; i < iPostOffset; i += 3 )
{
::swprintf_s( &(pBuf[i]), 4, _T("%.2X "), pMsg[j++] );
}
::swprintf_s( &(pBuf[i]), 3, _T("\r\n") );
TRACE(pBuf);
::free( pBuf );
#endif
}
TCHAR * GetCurrTime( void )
{
DWORD dwError = ERROR_SUCCESS;
TCHAR * ptRetVal = NULL;
#ifdef _DEBUG
int iTimeStrLen;
do
{
if ( (iTimeStrLen = ::GetTimeFormat( LOCALE_SYSTEM_DEFAULT, 0, NULL, NULL, NULL, 0 )) == 0 )
{
dwError = ::GetLastError();
TRACE(_T("%s : Failed getting time format.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), _T(__FUNCTION__), dwError, _T(__FILE__), __LINE__);
continue;
}
if ( (ptRetVal = (TCHAR *)::malloc( iTimeStrLen )) == NULL )
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
TRACE(_T("%s : Not enough memory.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), _T(__FUNCTION__), dwError, _T(__FILE__), __LINE__);
continue;
}
if ( ::GetTimeFormat( LOCALE_SYSTEM_DEFAULT, 0, NULL, NULL, ptRetVal, iTimeStrLen ) == 0 )
{
dwError = ::GetLastError();
TRACE(_T("%s : Failed getting time format.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), _T(__FUNCTION__), dwError, _T(__FILE__), __LINE__);
continue;
}
}
while ( 0 );
#endif
if ( dwError != ERROR_SUCCESS )
{
::free( ptRetVal );
ptRetVal = NULL;
}
::SetLastError( dwError );
return ptRetVal;
}
Just for kicks, here’s the function the PC lands in when the crash occurs (on the return statement of the last line of the function):
LPVOID CLinkList::Add( LPVOID pItem, DWORD len )
{
DWORD dwError = ERROR_SUCCESS;
LPVOID pItemCopy = NULL;
LPLIST_NODE_T ptNode = NULL;
do
{
// Validate parameters.
if ( (pItem == NULL) || (len == 0) )
{
dwError = ERROR_INVALID_PARAMETER;
TRACE(_T("CLinkList::Add : Invalid parameter.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
continue;
}
if ( this->m_blCopy == FALSE )
{
pItemCopy = pItem;
}
else if ( (pItemCopy = ::malloc( len )) == NULL )
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
TRACE(_T("CLinkList::Add : Failed to allocate memory.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
continue;
}
else
{
::memcpy( pItemCopy, pItem, len );
}
if ( (ptNode = (LPLIST_NODE_T)::malloc( sizeof(LIST_NODE_T) )) == NULL )
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
TRACE(_T("CLinkList::Add : Failed to allocate memory.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
continue;
}
ptNode->next = NULL;
ptNode->item = pItemCopy;
ptNode->len = len;
if ( this->m_ptFirstNode == NULL )
{
ptNode->prev = NULL;
this->m_ptFirstNode = ptNode;
}
else
{
ASSERT(this->m_ptLastNode != NULL);
ptNode->prev = this->m_ptLastNode;
this->m_ptLastNode->next = ptNode;
}
this->m_ptLastNode = ptNode;
this->m_dwItemCount++;
}
while ( 0 );
if ( dwError != ERROR_SUCCESS )
{
::free( ptNode );
if ( this->m_blCopy != FALSE )
{
::free( pItemCopy );
}
pItemCopy = NULL;
}
::SetLastError( dwError );
return pItemCopy;
}
This is the error, as printed in the Output Window:
First-chance exception at 0x7c936822
in ZCT.exe: 0xC0000005: Access
violation reading location 0x00000000.
HEAP[ZCT.exe]: Heap missing last entry
in committed range near 5451460
Windows has triggered a breakpoint in
ZCT.exe.This may be due to a corruption of the
heap, which indicates a bug in ZCT.exe
or any of the DLLs it has loaded.This may also be due to the user
pressing F12 while ZCT.exe has focus.The output window may have more
diagnostic information. The program
‘[0x9F4] ZCT.exe: Native’ has exited
with code 0 (0x0).
Any ideas?
Will allocate a number of bytes when you probably want to allocate that number of
wchar_ts.