?? memrecord.cpp
字號(hào):
#include "MemRecord.h"MemRecord appMemory;#if defined( MEM_DEBUG )char DELETE_FILE[ FILENAME_LENGTH ] = {0};int DELETE_LINE = 0;CCommonMutex globalLock;stack<DELINFOSTACK> globalStack;void BuildStack(){ DELINFOSTACK stDis = {"",0}; strcpy(stDis.Filename, DELETE_FILE); stDis.LineNum = DELETE_LINE; globalStack.push(stDis);}void* operator new( size_t nSize, char* pszFileName, int nLineNum ){ MemOperation record; void *pResult; pResult = ::operator new( nSize ); if ( pResult ) { // record the alloc memory strncpy( record.Filename, pszFileName, FILENAME_LENGTH - 1 ); record.Filename[ FILENAME_LENGTH - 1 ] = '\0'; record.LineNum = nLineNum; record.AllocSize = nSize; record.OperationType = SINGLE_NEW; record.errCode = 0; record.pBuffer = pResult; appMemory.Insert( pResult, &record ); } return pResult;}void* operator new[]( size_t nSize, char* pszFileName, int nLineNum ){ MemOperation record; void *pResult; pResult = ::operator new[]( nSize ); if ( pResult ) { // record the alloc memory strncpy( record.Filename, pszFileName, FILENAME_LENGTH - 1 ); record.Filename[ FILENAME_LENGTH - 1 ] = '\0'; record.LineNum = nLineNum; record.AllocSize = nSize; record.OperationType = ARRAY_NEW; record.errCode = 0; record.pBuffer = pResult; appMemory.Insert( pResult, &record ); } return pResult;}void operator delete( void *ptr ){ if ( NULL == ptr ) { globalLock.Unlock(); return; } MemOperation record; strncpy( record.Filename, DELETE_FILE, FILENAME_LENGTH - 1 ); record.Filename[ FILENAME_LENGTH - 1 ] = '\0'; record.LineNum = DELETE_LINE; record.AllocSize = 0; // Unknown, but compiler known record.OperationType = SINGLE_DELETE; record.errCode = 0; record.pBuffer = ptr; strcpy( DELETE_FILE , "" ); DELETE_LINE = 0 ; globalLock.Unlock(); appMemory.Erase( ptr, &record ); free( ptr );}voidoperator delete[]( void *ptr ){ if ( NULL == ptr ) { globalLock.Unlock(); return; } MemOperation record; strncpy( record.Filename, DELETE_FILE, FILENAME_LENGTH - 1 ); record.Filename[ FILENAME_LENGTH - 1 ] = '\0'; record.LineNum = DELETE_LINE; record.AllocSize = 0; // Unknown, but compiler known record.OperationType = ARRAY_DELETE; record.errCode = 0; record.pBuffer = ptr; strcpy( DELETE_FILE , "" ); DELETE_LINE = 0 ; globalLock.Unlock(); appMemory.Erase( ptr, &record ); free( ptr );}static void interruptHandler( int signo );void DecodeErr( int ErrNum );static void interruptHandler( int signo ){ char msgPath[ 128 ]; appMemory.GetMsgFilePath( msgPath );/* switch( signo ) { case SIGINT: printf( "SIGINT" ); break; case SIGQUIT: printf( "SIGQUIT" ); break; case SIGABRT: printf( "SIGABRT" ); break; case SIGKILL: printf( "SIGKILL" ); break; case SIGSEGV: printf( "SIGSEGV" ); break; default: printf( "SIGNO = %d", signo ); break; } printf( " 信號(hào), 將刪除消息隊(duì)列\(zhòng)n" ); printf( "正在刪除消息隊(duì)列, 稍等......\n" );*/ int nRtn = msgctl( appMemory.GetMsgQueue(), IPC_RMID, NULL ); // delete the message queue if (nRtn == -1) {/* switch( errno ) { case EAGAIN: printf( "---EAGAIN---\n" ); break; case EACCES: printf( "---EACCES---\n" ); break; case EFAULT: printf( "---EFAULT---\n" ); break; case EIDRM: printf( "---EIDRM---\n" ); break; case EINTR: printf( "---EINTR---\n" ); break; case EINVAL: printf( "---EINVAL---\n" ); break; case ENOMEM: printf( "---ENOMEM---\n" ); break; default: printf( "---Undefined---\n" ); break; }*/ printf("MemRecord Cleaner: Sorry, I am failed to delete the MSG QUEUE. please use ipcrm to delete msgqueue %d.\r\n", appMemory.GetMsgQueue()); }// printf( "成功刪除消息隊(duì)列\(zhòng)n" );// printf( "正在刪除文件\"%s\", 稍等......\n", msgPath ); nRtn = unlink( msgPath );// if ( 0 == nRtn )// printf( "刪除文件\"%s\"成功\n", msgPath ); exit( 1 );}void DecodeErr( int ErrNum ){ switch( ErrNum ) { case EAGAIN: printf( "---EAGAIN---\n" ); break; case EACCES: printf( "---EACCES---\n" ); break; case EFAULT: printf( "---EFAULT---\n" ); break; case EIDRM: printf( "---EIDRM---\n" ); break; case EINTR: printf( "---EINTR---\n" ); break; case EINVAL: printf( "---EINVAL---\n" ); break; case ENOMEM: printf( "---ENOMEM---\n" ); break; default: printf( "---Undefined---\n" ); break; }}MemRecord::MemRecord(){ m_pidMain = getpid(); /** * create a message queue if the message not exist, else delete the * existed message queue first and then create it. */ key_t key; int flags, counter = 0; struct passwd *pwd; FILE *fp = NULL;// m_pidChild = -1 ; // POSIX函數(shù), getpwend()在POSIX中沒(méi)有定義(svr4中定義了)故這里沒(méi)有使用getpwent() // 取得運(yùn)行該進(jìn)程的用戶(hù)的缺省目錄 if ( NULL == (pwd = getpwuid( getuid() ) ) ) { printf( "MemRecord : Failed to get current users information.\r\n" ); exit( 1 ); } sprintf( m_szMsgPath, "%s/.MemMsgQueue%d", pwd->pw_dir, m_pidMain ); // 確保m_szMsgPath表示的文件存在, 否則計(jì)算創(chuàng)建消息隊(duì)列成功 // 其key值也將是0XFFFFFFFF(-1)。 // 如果文件不存在則創(chuàng)建, 創(chuàng)建不成功則嘗試10次 do { // Open for reading and appending (writing at end of file). The // file is created if it does not exist fp = fopen( m_szMsgPath, "a+" ); if ( fp ) break; } while( counter++ < 10 ); if ( NULL == fp ) { printf( "MemRecord : Cannot create symbol file for Msg queue: %s\n", m_szMsgPath ); exit( 1 ); } key = ftok( m_szMsgPath, 'a' ); if ( -1 == key ) { printf( "MemRecord : Cannot Create KEY for MemRecord Message queue.\r\n" ); exit( 1 ); } /** * use msgget with IPC_CREATE param to get the message queue id * if the mesasge queue exist, else create it. */ m_nMsgQueue = msgget( key, IPC_CREAT ); if( m_nMsgQueue != -1 ) // the message queue exist then delete it { // delete the message queue if ( msgctl( m_nMsgQueue, IPC_RMID, NULL ) == -1 ) { printf( "MemRecord : Cannot Delete the old Message queue, please delete them with ipcrm and retry.\r\n" ); exit( 1 ); // need modify because the failure of delete // message queue cannot exit the system } } /** * the code below guarantee that the message queue with "key" value * must be delete whether exist. * * create the message queue again with "key" value */ flags = IPC_CREAT | IPC_EXCL | 0666; m_nMsgQueue = msgget( key, flags ); if ( m_nMsgQueue == -1 ) { printf( "MemRecord : Cannot create the Message Queue.\r\n" ); exit( 1 ); } /////////////////////////////////////////////////////////////////////////// // 啟動(dòng)一個(gè)孤兒進(jìn)程來(lái)監(jiān)視被監(jiān)控進(jìn)程的情況,如被監(jiān)控進(jìn)程退出,則清除所創(chuàng)建的文件標(biāo)識(shí)和消息隊(duì)列 pid_t pidChild; if ( ( pidChild = fork() ) < 0 ) { printf( "MemRecord : Failed to Create ChildProcess which is used to do cleanup.\r\n" ); exit( 1 ); } else if ( 0 == pidChild ) { pid_t pidGrandson = fork(); if (pidGrandson < 0) { printf( "MemRecord : Failed to Create ChildProcess which is used to do cleanup.\r\n" ); exit( 1 ); } else if (pidGrandson == 0) { char buf1[32] = {0}; char buf2[32] = {0}; char buf3[32] = {0}; char buf4[128] = {0}; strcpy(buf1, "./MemCleaner"); sprintf(buf2, "%d",appMemory.GetMainProcessPid()); sprintf(buf3, "%d",appMemory.GetMsgQueue()); appMemory.GetMsgFilePath( buf4 ); execlp("./MemCleaner", buf1, buf2, buf3, buf4, 0); } else { exit(0); } } else { int status; wait(&status); } ///////////////////////////////////////////////////////////////////////////}MemRecord::~MemRecord(){ if (!m_mapMemory.empty() || !m_listMemory.empty()) { printf("MemRecord : We think there's some memory leak happened, please check the leak.rec file for detail.\r\n"); // Truncate file to zero length or create text file for writing FILE *fp = fopen( "leak.rec", "w" ); if ( NULL == fp ) // if fail to open the file, assignment stdout to it { fp = stdout; } fprintf( fp, "Memory leak %d times, description as below:\n\n", m_mapMemory.size() + m_listMemory.size() ); fprintf( fp, "%-24s%-16s%-16s%-16s%-8s%s\n", "FILE NAME", "LINE NUMBER", "MEMORY SIZE", "POINTER", "ALLOC", "LEAK REASON" ); fprintf( fp, "------------------------------------------------" "------------------------------------------------\n" ); // print the content of m_mapMemory and m_listMemory to leak.rec file map<void *, MemOperation>::iterator mapIterator = m_mapMemory.begin(); char *types[2] = { "new", "new[]" }; char *err[2] = { "not free", "use delete" }; // output the content of m_mapMemory to file while( mapIterator != m_mapMemory.end() ) { fprintf( fp, "%-24s%-16d%-16d%-#16X%-8s%s\n", mapIterator->second.Filename, mapIterator->second.LineNum, mapIterator->second.AllocSize, mapIterator->second.pBuffer, types[ mapIterator->second.OperationType % 2 ], err[ mapIterator->second.errCode ] ); fflush( fp ); mapIterator++; } list<MemOperation>::iterator record; // output the content of m_listMemory to file for ( record = m_listMemory.begin(); record != m_listMemory.end(); record++ ) { fprintf( fp, "%-24s%-16d%-16d%-#16X%-8s%s\n", record->Filename, record->LineNum, record->AllocSize, record->pBuffer, types[ record->OperationType % 2 ], err[ record->errCode ] ); fflush( fp ); } fprintf( fp, "------------------------------------------------" "------------------------------------------------\n" ); }// int rc = msgctl( m_nMsgQueue, IPC_RMID, NULL ); // delete the message queue// char cmd[64];// if ( 0 != rc ) printf("MemRecord : Sorry, I am failed to delete the MSG QUEUE. please use ipcrm to delete msgqueue %d.\r\n", appMemory.GetMsgQueue());// unlink( m_szMsgPath );// m_mutexRecord.Unlock();// sprintf( cmd, "kill -9 %d", m_pidChild );// // 當(dāng)程序正常結(jié)束的時(shí)候?qū)⒆舆M(jìn)程殺掉, 不然子進(jìn)程將會(huì)變?yōu)楣聝?/span>// system( cmd ); }voidMemRecord::Insert( void *pBuffer, MemOperation *pRecord ){ MemOperation record; MsgBuffer SendMsg; static bool firstError = true; if ( !pBuffer || !pRecord ) { return; } m_mutexRecord.Lock(); // insert to the new/new[] operation to member data m_mapMemory memcpy( ( void * ) &record, pRecord, sizeof( MemOperation ) ); pair<void *, MemOperation> value(pBuffer, record); if ( m_nMsgQueue != -1 ) // send a message to message queue if the message queue available { int rc; struct msqid_ds msgInfo; if ( 0 == msgctl( m_nMsgQueue, IPC_STAT, &msgInfo ) ) { if ( msgInfo.msg_qbytes > ( msgInfo.msg_cbytes + sizeof( MemOperation ) + 4 ) ) { memcpy( ( void * ) &SendMsg.Data, pRecord, sizeof( MemOperation ) ); SendMsg.Data.errCode = 0; // indicate new operation, it is use for message queue only SendMsg.Type = MEMORY_INFO; rc = msgsnd( m_nMsgQueue, &SendMsg, sizeof( SendMsg.Data ), IPC_NOWAIT ); if ( rc == -1 ) // fail to send { //DecodeErr( errno ); printf( "MemRecord : Error when try to send data from Message queue.\r\n" ); } else firstError = true; } } else { if ( firstError ) { //DecodeErr( errno ); //printf( "在檢查消息隊(duì)列的屬性時(shí)出錯(cuò)\n" ); firstError = false; } } } m_mapMemory.insert( value ); m_mutexRecord.Unlock();}intMemRecord::Erase( void *pBuffer, MemOperation *pRecord ){ map<void *, MemOperation>::iterator record; MsgBuffer SendMsg; static bool firstError = true; if ( !pBuffer || !pRecord ) { return -1; } if((!strcmp(pRecord->Filename,""))&&(pRecord->LineNum == 0)) { record = m_mapMemory.find( pBuffer ); // if the global delete info is empty and cannot find this // pointer in our map, that mean the pointer of this delete request // is not "new" by us. so just drop it if ( record == m_mapMemory.end() ) { return -1; } // if we can find the pointer in our map but the global delete info // is zero, it maybe a "recursion(遞歸) delete", so if stack isn't empty we will // pop the corresponding delete info in the stack and go on. if (!globalStack.empty()) { DELINFOSTACK stDis = globalStack.top(); strcpy(pRecord->Filename, stDis.Filename); pRecord->LineNum = stDis.LineNum; globalStack.pop(); } } m_mutexRecord.Lock(); if ( m_nMsgQueue != -1 ) // send a message to message queue if the message queue available { int rc; struct msqid_ds msgInfo; // 取得消息隊(duì)列的屬性 rc = msgctl( m_nMsgQueue, IPC_STAT, &msgInfo ); if ( 0 == rc ) { // 判斷消息隊(duì)列是否還有空間可用 if ( msgInfo.msg_qbytes > ( msgInfo.msg_cbytes + sizeof( MemOperation ) + 4 ) ) { memcpy( ( void * ) &SendMsg.Data, pRecord, sizeof( MemOperation ) ); SendMsg.Data.errCode = 1; SendMsg.Type = MEMORY_INFO; rc = msgsnd( m_nMsgQueue, &SendMsg, sizeof( SendMsg.Data ), IPC_NOWAIT ); if ( rc == -1 ) // 如果出錯(cuò)則給出相應(yīng)的提示 { //DecodeErr( errno ); printf( "MemRecord : Error when try to send data from Message queue.\r\n" ); } else firstError = true; } } else { if ( firstError ) { //DecodeErr( errno ); //printf( "在檢查消息隊(duì)列的屬性時(shí)出錯(cuò)\n" ); firstError = false; } } } record = m_mapMemory.find( pBuffer ); if ( record != m_mapMemory.end() ) { bool bError = ( SINGLE_DELETE == pRecord->OperationType ) && ( ARRAY_NEW == record->second.OperationType ); MemOperation temp; if ( bError ) // error if alloc with new[] type and free with delete type { memcpy( &temp, &( record->second ), sizeof( MemOperation ) ); temp.errCode = 1; m_listMemory.push_back( temp ); } m_mapMemory.erase( record ); m_mutexRecord.Unlock(); return 0; } else { // delete a memory pointer that no-existed or alloc with new[] type // it will cause the uncertain result, so I will give a warning message on screen printf( "MemRecord : *****WARNING: At %s line %ld -- %#x, You delete a pointer that cannot find in MAP.******\n", pRecord->Filename, pRecord->LineNum , pBuffer); m_mutexRecord.Unlock(); return -2; }}voidMemRecord::GetMsgFilePath( char *path ){ if ( NULL == path ) return; strcpy( path, m_szMsgPath ); return;}#endif
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -