객체 소멸시 invalid pointer 발생.

ar의 이미지

 
	BaseThread *pBaseThr ;
	NBThr_Iterator itThrMap;
	for ( itThrMap = m_ThreadMap.begin(); itThrMap != m_ThreadMap.end(); itThrMap++ )
	{
		pBaseThr = (BaseThread *)itThrMap->second;
		if ( pBaseThr->GetExitType() == BaseThread::ThrExit_State_Detachable ) {
			if ( pBaseThr->GetCurState() == BaseThread::ThrCur_State_Terminated )
			{
				pBaseThr->Terminate();
				m_ThreadMap.erase(pBaseThr->GetThrIdx());
				delete pBaseThr;
DEBUG_MSG_STR("Deleted!!");
			}
		} else {
			if ( pBaseThr->GetCurState() == BaseThread::ThrCur_State_Zombie )
			{
				pBaseThr->Terminate();
				m_ThreadMap.erase(pBaseThr->GetThrIdx());
				delete pBaseThr;
DEBUG_MSG_STR("Deleted!!");
			}
		}
	}

BaseThread 는 서버 프로세스에서 accept 되면 생성해주는 쓰레드이고, 직접적인 통신을 담당합니다.
문제는 커넥션이 해제되었고, 쓰레드는 종료되었는데 위의 코드에서 아래와 같은 오류가 발생합니다. 도무지 감이 안오네요..
delete 부분만 주석처리하면 물론 정상 동작합니다.

*** glibc detected *** ./a.out: free(): invalid pointer: 0x09d7e1fc ***
======= Backtrace: =========
/lib/tls/i686/cmov/libc.so.6[0x3540d1]
/lib/tls/i686/cmov/libc.so.6[0x3557d2]
/lib/tls/i686/cmov/libc.so.6(cfree+0x6d)[0x3588ad]
/usr/lib/libstdc++.so.6(_ZdlPv+0x21)[0x1c86f1]
./a.out[0x804b17e]
./a.out[0x8049853]
./a.out[0x80495a5]
./a.out[0x8049aa5]
./a.out[0x804bc5f]
./a.out[0x804bccb]
/lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe6)[0x2ffb56]
./a.out[0x8049241]
======= Memory map: ========
00110000-001f6000 r-xp 00000000 08:06 10353      /usr/lib/libstdc++.so.6.0.13
001f6000-001fa000 r--p 000e6000 08:06 10353      /usr/lib/libstdc++.so.6.0.13
001fa000-001fb000 rw-p 000ea000 08:06 10353      /usr/lib/libstdc++.so.6.0.13
001fb000-00202000 rw-p 00000000 00:00 0
00202000-0021e000 r-xp 00000000 08:06 679989     /lib/libgcc_s.so.1
0021e000-0021f000 r--p 0001b000 08:06 679989     /lib/libgcc_s.so.1
0021f000-00220000 rw-p 0001c000 08:06 679989     /lib/libgcc_s.so.1
002e9000-00427000 r-xp 00000000 08:06 110655     /lib/tls/i686/cmov/libc-2.10.1.so
00427000-00428000 ---p 0013e000 08:06 110655     /lib/tls/i686/cmov/libc-2.10.1.so
00428000-0042a000 r--p 0013e000 08:06 110655     /lib/tls/i686/cmov/libc-2.10.1.so
0042a000-0042b000 rw-p 00140000 08:06 110655     /lib/tls/i686/cmov/libc-2.10.1.so
0042b000-0042e000 rw-p 00000000 00:00 0
00503000-0051e000 r-xp 00000000 08:06 157916     /lib/ld-2.10.1.so
0051e000-0051f000 r--p 0001a000 08:06 157916     /lib/ld-2.10.1.so
0051f000-00520000 rw-p 0001b000 08:06 157916     /lib/ld-2.10.1.so
0068c000-0068d000 r-xp 00000000 00:00 0          [vdso]
00abe000-00ae2000 r-xp 00000000 08:06 127622     /lib/tls/i686/cmov/libm-2.10.1.so
00ae2000-00ae3000 r--p 00023000 08:06 127622     /lib/tls/i686/cmov/libm-2.10.1.so
00ae3000-00ae4000 rw-p 00024000 08:06 127622     /lib/tls/i686/cmov/libm-2.10.1.so
00fe1000-00ff6000 r-xp 00000000 08:06 665247     /lib/tls/i686/cmov/libpthread-2.10.1.so
00ff6000-00ff7000 r--p 00014000 08:06 665247     /lib/tls/i686/cmov/libpthread-2.10.1.so
00ff7000-00ff8000 rw-p 00015000 08:06 665247     /lib/tls/i686/cmov/libpthread-2.10.1.so
00ff8000-00ffa000 rw-p 00000000 00:00 0
08048000-0804e000 r-xp 00000000 08:06 91184      /home/keona/www/ServLib/src/a.out
0804e000-0804f000 r--p 00005000 08:06 91184      /home/keona/www/ServLib/src/a.out
0804f000-08050000 rw-p 00006000 08:06 91184      /home/keona/www/ServLib/src/a.out
09d7d000-09d9f000 rw-p 00000000 00:00 0          [heap]
b6700000-b6721000 rw-p 00000000 00:00 0
b6721000-b6800000 ---p 00000000 00:00 0
b6885000-b6886000 ---p 00000000 00:00 0
b6886000-b7086000 rw-p 00000000 00:00 0
b7086000-b7087000 ---p 00000000 00:00 0
b7087000-b788a000 rw-p 00000000 00:00 0
b789e000-b78a1000 rw-p 00000000 00:00 0
bfb50000-bfb65000 rw-p 00000000 00:00 0          [stack]
Aborted

neogeo의 이미지

코드내용상으로는 알기 힘드네요.

m_ThreadMap.erase(pBaseThr->GetThrIdx());

부분에서 Map 이 저 Idx 해당하는 내용을 지우면서 어떤 동작을 하나 확인해보세요. 잘은 모르겠지만 pBaseThr 이 pointing 하는 부분이 이미 저 code 에서 destruction 되고 있을지도 모릅니다.

Neogeo - Future is Now.

Neogeo - Future is Now.

ar의 이미지

아.. 맵은 아래와 같이 선언된 것이구요.. 맵에서 erase 후에도 pBaseThr 객체에는 아무런 영향이 없습니다.
단지 맵에서만 제거한 것일뿐.. 맵을 순차적으로 돌면서 통신이 종료된 객체들을 삭제하는 것인데.. 도무지 감이 안오네요..

typedef map<int, BaseThread*>::iterator  NBThr_Iterator;

아래의 코드처럼 BaseThread 쓰레드를 생성후 Start 호출하여 pthread를 생성합니다. 통신이 종료될때
Run 함수가 종료되고 분명 쓰레드는 pthread_exit로 종료된 것 같습니다. 그렇다면.. 더이상 필요치 않는
저 객체를 부모 프로세스에서 delete 하는데 아무런 문제가 없는 것 같은데.. 답답하네요.. ㅡ.ㅜ
명시적으로 delete 해주지 않아도 되는 JAVA가 그리워지는 하루입니다 ㅡ.ㅜ

int BaseThread::Start()
{
	int nResult = 0;
 
	if ( (pthread_create(&m_nID, NULL, StartPoint, reinterpret_cast<void *>(this))) == 0 ) {
		if ( m_nExitCode == ThrExit_State_Detachable ) {
			pthread_detach(m_nID);
		}
	} else {
		SetState(ThrCur_State_Aboarted);
		nResult = -1;
	}
	return nResult;
}
 
void* BaseThread::StartPoint(void* pParam)
{
	BaseThread* pThis = reinterpret_cast<BaseThread*>(pParam);
	pThis->SetState(ThrCur_State_Running);
 
	pThis->Run();
 
	if ( pThis->GetExitType() == ThrExit_State_Detachable ) {
		pThis->SetState(ThrCur_State_Terminated);
	} else {
		pThis->SetState(ThrCur_State_Zombie);
	}
DEBUG_MSG();
	pthread_exit((void*)NULL);
 
	return NULL;
}
neogeo의 이미지

일단 맵관련 부분은 multi thread 랑 관계가 없다는 가정하에,

가장 문제가 될 부분은 void* BaseThread::StartPoint(void* pParam) 가 실행되고 있는 도중에 return 되기 직전에 그 객체가 delete 될 가능성이 존재할것 같습니다.

StartPoint 가 만약 static 함수면 괜찮을지도 모르겠지만 아니라면 return 될때까지 pThis 가 delete 되지 않음을 보장할 필요가 있을것 같습니다.

대충 상황을 설명하면 이렇게 될 가능성이 있습니다.

class A {
    public:
        void test(void);
};
 
void global_test(A* a )
{
    delete a;
}
 
void A::test(void)
{
    global_test(this);
    return;
}
 
int main(int argc,char** argv)
{
    A a;
    a.test();
}

전체코드를 보지 않아서 뭐라고 이야기 하기 힘듭니다만, 디버거를 붙여서 delete 하고 난뒤 어디서 잘못된 pointer 를 access 하나 확인해보심이 좋을 듯 합니다.

Neogeo - Future is Now.

Neogeo - Future is Now.

shyblue의 이미지

BaseThread class의 소멸자를 확인해 보시는편이 좋을듯합니다.
소멸자내에서 처리중에 오류가 난것으로 예상이 되는데요.
BaseThread가 상속받은 클래스면, 부모클래스의 소멸자가 virtual로 선언되어 있는지도 확인하시고...
여튼, 상기 코드에서 딱히 눈에 보이는 부분은 없는걸로 봐서, 소멸자 호출후에 생기는 문제인 것으로 보이고
디버거에서 소멸자내에 break 거시고 따라가시보시는것도 방법일겁니다.

時日也放聲大哭

時日也放聲大哭

ar의 이미지

헉.. BaseThread의 소멸자에서 제가 실수를 했네요..
객체 멤버에 char m_szName[256]; 이렇게 들어있는데.. 이걸
delete []m_szName; 해버렸네요.. 동적으로 할당한게 아니라서 이렇게 delete하면 안되는군요..
C/Java 개발만 하다가 C++ 코딩하는데.. 여러모로 손에 안익네요.. ㅡ.ㅜ
암튼 감사합니다 ^^

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.