블로그는 나의 힘!
[ Programing ]/C++2009. 12. 30. 17:30
메모리 침범에 대해 말해 봅시다.
설계를 하다가 보면 아무 이상 없고, 동작도 문제 없으나 어느 순간 갑자기 데이터가 바뀌거나, 심각한 오류가 날때가 있습니다.

아무리 코드를 찾아도 이상이 없는데 말이죠... 이러면 방법은 디버그에서 동적으로 선언한 것이 있으면 그 안의 데이터와 주소를 뚫어지게 쳐다 봐야 합니다.  여기 밖에 없거든요...

근데 어느 순간 갑자기 주소값이 변할때가 있다면, 메모리 침범을 의심해야 합니다.


class cImportance
{

public: 
        enum BUFFER_INDEX_ { ...... };
enum TYPENAME_ { ...... };
enum PRINCIPAL_ { ...... };
struct _sPrincipal 
       {
long int            nSize;            // Data size
TYPENAME_    eType;          // Data TYPE
void*               pvData;          // Data information

_sPrincipal() : nSize( 0 ), eType( TYPENAME_INIT ), pvData( NULL ) {}
       };

protected:

private:
long int         m_nSize[BUFFER_INDEX_MAX];           // Memory Max size
        char*            m_cBuffer[BUFFER_INDEX_MAX];         // Put data buffer ( Index 0 ~ 5 )
        _sPrincipal    m_sPrincipal[PRINCIPAL_MAX];
private:
bool Initial();          // 초기화, 생성
bool Release();     // 삭제, 해제
protected:
BUFFER_INDEX_ IsBufferIndex();
long int Is_sPrincipalSize( _sPrincipal& _sData );
public:
cImportance();
cImportance( const cImportance& rhsImportance );
~cImportance();

bool Clear();         // 데이터 초기화

bool LoadData( PRINCIPAL_ eIndex );       // 버퍼에 데이터를 불러온다.
        bool SaveData( PRINCIPAL_ eIndex );       // 버퍼에 데이터를 복사한다.
};

=============================== cpp =====================================

bool cImportance::Initial()
{
ZeroMemory( m_nSize, sizeof( long int ) *BUFFER_INDEX_MAX );
ZeroMemory( m_cBuffer, sizeof( char* ) *BUFFER_INDEX_MAX );
for( long int i = 0; i < BUFFER_INDEX_MAX; i++ )
m_cBuffer[i] = new char[BUFFER_SIZE];

return true;
}

bool cImportance::Release()
{
SAFE_DELETE( m_cMd5 );

for( long int i = 0; i < BUFFER_INDEX_MAX; i++ )
SAFE_DELETE_ARRAY( m_cBuffer[i] );
return true;
}

bool cImportance::SaveData( PRINCIPAL_ eIndex )
{
if( NULL == m_sPrincipal[eIndex].pvData ) return false;

long int nSize = 0;
long int nBufferIndex = IsBufferIndex() +( Is_sPrincipalSize( m_sPrincipal[eIndex] ) *eIndex );

// >>> void* Data Information Size Input
  memcpy( m_cBuffer +nBufferIndex, &m_sPrincipal[eIndex].nSize, sizeof( long int ) );
nSize += sizeof( long int );

// >>> void* Data Information Type Input
memcpy( m_cBuffer +nBufferIndex +nSize, &m_sPrincipal[eIndex].eType, sizeof( TYPENAME_ ) );
nSize += sizeof( TYPENAME_ );

// >>> void* Data Information
  memcpy( m_cBuffer +nBufferIndex +nSize, m_sPrincipal[eIndex].pvData, m_sPrincipal[eIndex].nSize );
nSize += m_sPrincipal[eIndex].nSize;

return true;
}

위 코드를 보면 전혀 이상이 없습니다. 
버퍼 배열을 일일이 주소 지정하며 접근 하며 (복잡하긴 하지만), 데이터도 복사하고, 크게 지장이 없으나, 가끔식 갑자기 특히 m_sPrincipal[eIndex].pvData에서 주소값이 바뀔때가 있습니다. 
이유는 메모리 주소 침범, 정적으로 선언된 변수에 동적으로 선언된 변수가 new 로 생성 하면서 침범 당한 경우입니다.

이런 경우 동적으로 같이 선언하여 꼼꼼하게 관리하거나, 아니면 정적인 변수를 위로, 동적인 변수를 아래로 설계하는 생각을 가집시다.

ex )
< 문제점 >
private:
long int         m_nSize[BUFFER_INDEX_MAX];
        char*            m_cBuffer[BUFFER_INDEX_MAX];
        _sPrincipal    m_sPrincipal[PRINCIPAL_MAX];

동적인 변수가 정적 변수를 침범했다. 
new로 m_cBuffer 할당시 할당할 공간이 크다면 m_sPrincipal 공간 침범 가능성이 커진다.

< 해결법1 >
private:
long int         m_nSize[BUFFER_INDEX_MAX];
        _sPrincipal    m_sPrincipal[PRINCIPAL_MAX];
        char*            m_cBuffer[BUFFER_INDEX_MAX];

동적인 변수를 아래로 내려서 설계 자체에서 침범 자체를 고려해서 설계 한다.

< 해결법2>
private:
long int         m_nSize[BUFFER_INDEX_MAX];
        char*            m_cBuffer[BUFFER_INDEX_MAX];
        _sPrincipal*   m_sPrincipal[PRINCIPAL_MAX];

Initial()에 m_sPrincipal[] 변수도 new 생성해 동적 선언한다. 
역시 Release()에서 반드시 해제해야 하는 철저한 메모리 관리 필요.

Posted by Mister_Q