memwatch 를 사용하여 프로그램이 죽는 원인을 파악하던중
memwatch 툴을 사용하여 메모리 누수 및 문제점을 찾고 있습니다.
프로그램은 다중쓰레드를 사용하는(약 50개) 프로그램입니다. memwatch에는 이러한 내용의 로그가 생성되는데요
relink: <477577> cta.h(370) attempting to repair MW-0x812a998...
relink: failed for MW-0x812a998; reverse chain fragmented at MW-0x812a038, 'prev' is 0x812a9f0
relink: <477577> cta.h(370) attempting emergency repairs...
relink: forward chain's last intact MW is MW-0x812aa38, 100 bytes at cta.h(362)
relink: forward chain's first damaged MW is MW-0x812a998, 100 bytes at cta.h(362)
relink: reverse chain's last intact MW is MW-0x811a360, 1200 bytes at cta.c(469)
relink: reverse chain's first damaged MW is MW-0x811a840, 1200 bytes at cta.c(469)
relink: emergency repairs successful, assessing damage...
relink: partial, 51 MW-blocks of 59036 bytes lost
internal: <477577> cta.h(370), mwIsOwned fails for MW-0x812a998
double-free: <477577> cta.h(370), 0x812a9bc was freed from cta.c(678)
relink: <943234> cta.c(678) attempting to repair MW-0x812aa90...
relink: MW-0x812aa90 not found in forward chain search
relink: MW-0x812aa90 not found in reverse chain search
relink: heap appears intact, MW-0x812aa90 probably garbage pointer
relink: partial, 52 MW-blocks of 59073 bytes lost
internal: <943234> cta.c(678), mwIsOwned fails for MW-0x812aa90
WILD free: <943234> cta.c(678), unknown pointer 0x812aab4
relink: <1047946> cta.c(678) attempting to repair MW-0x812aa38...
relink: MW-0x812aa38 is the head (first) allocation
relink: MW-0x812aa38 not found in reverse chain search
relink: heap verification FAILS - aborting program
어떻게 수정을 해야 할지 모르겠습니다. 더블프리가 나는 부분에선 아무리 따져봐도 더블프리가 일어 날수가 없는데
저런 로그가 생기구요 (잘못본건지.. 여러번 확인했습니다만) 혹 memwatch는 다중쓰레드에선 제대로 기능을 하지
못하는건 아닌가 하는 생각이 들기도 하고 머가 잘못된것인지 고수님들의 많은 조언 부탁드립니다.
그럼 오늘 하루도 행복한 하루되시길...
음.. 모든 쓰레드들이 realloc을 자주 사용하는데요
혹시 realloc이 문제의 소지가 있는것인가요? 로그에 나오는 relink라는 건 realloc을 일컽는건 아닌지 해서요
더블 프리가 의심된다면
소스상에서 free(ptr) 을
로 교체하세요. 매크로 함수로 만드는게 낫겠죠.
아니면 포인터 자체를 한번 더 싸서 alloc 하는 위치랑
free 하는 위치를 추적하시는게 빠를겁니다.
답변감사 합니다. 소스상의 모든 프리는 ..
#define Free(x) if(x != NULL){free(x); x = NULL;}
를 사용하여 프리 합니다.
방금은 이런 간결한 로그가 생성되면서 죽었네요
============= MEMWATCH 2.71 Copyright (C) 1992-1999 Johan Lindh =============
Started at Tue May 9 12:35:20 2006
Modes: __STDC__ 32-bit mwDWORD==(unsigned long)
mwROUNDALLOC==4 sizeof(mwData)==32 mwDataSize==32
relink: <46351> cta.c(678) attempting to repair MW-0x812a9f0...
relink: MW-0x812a9f0 not found in forward chain search
relink: heap verification FAILS - aborting program
버퍼 오버플로우나 언더플로우가 있는지 확인해 보세요.
memwatch 를 사용해 보지 않아서 memwatch 가 버퍼오버플로우나 언더플로우까지 잡아 주는지는 모르겠네요
혹시 memwatch 가 버퍼오버플로우를 잡지 않는다면 버퍼오버플로우가 발생하지 않았는지 알아보세요
해당 alloc/free 부분에 아무리 봐도 이상이 없다면, 다른 코드에서 alloc 정보를 망가뜨릴수가 있는데요
alloc 정보를 망가뜨리는 대부분의 경우가 버퍼 오버/언더 플로우입니다.
답변 감사드립니다. 제가 알기론 오버/언더 플로우도 감지 ..
감지 하여 로그에 남깁니다.. ㅎㅎ 사용해보지 않으신분들을 위해 잠시 소개 해드리면
http://www.linkdata.se/sourcecode.html 주소에서 다운받아서 사용하실수 있습니다 프리구요
더블프리, 언프리, 오버/언더 플로우, 등등.. 입니다.
multi-thread 환경이라면...
Free() 가 실행되는 도중에 racing condition이 발생할 수도 있지 않을까요? 그다지 확률이 높은 건 아니지만, thread가 50개씩이나 된다고 하면 가능할 것도 같습니다.
답변 감사 합니다.
레이싱 컨디션도 생각을 해봤는데 Free()에들어가는 변수들(char *) 들은 모두 쓰레드의 지역변수들인데
발생할 소지가 있을까요? 혹시 Free()가 define 인것이 발생 소지가 있는건가요?
조금만더 자세히 말씀해주실수 있을지..... 아니면 malloc realloc free 함수들이 쓰레드 세이프하지
않은건 아닌지..(이건 아닐꺼라 생각하지만 너무 막막하다보니)
참고로 이런 테스트를 해봤습니다. memwatch로 로그도 찍으면서요 아래 코드를 잠시.. 보시면
int main(int argc, char **argv)
{
int i;
pthread_t p_thread;
for(i = 0; i 작으면 20; i++)
{
pthread_mutex_lock(&Async_Mutex);
pthread_create(&p_thread, NULL, thread_malloc, (void *)&i);
pthread_cond_wait(&Async_Cond, &Async_Mutex);
pthread_mutex_unlock(&Async_Mutex);
}
pause();
}
void *thread_malloc(void *data)
{
char *tmp = NULL;
pthread_mutex_lock(&Async_Mutex);
printf("Start Thread %d\n",*((int *)data));
pthread_cond_signal(&Async_Cond);
pthread_mutex_unlock(&Async_Mutex);
while(1)
{
//pthread_mutex_lock(&Malloc_Mutex);
tmp = (char *)malloc(1024);
//pthread_mutex_unlock(&Malloc_Mutex);
//Free(tmp);
if(tmp != NULL)
{
//pthread_mutex_lock(&Free_Mutex);
free(tmp);
//pthread_mutex_unlock(&Free_Mutex);
tmp = NULL;
}
}
}
이런것두 똑같은 에러로 죽더군요 중간에 주석처리된 부분 보시면 아시겠지만 뮤텍스를 이용해봐도
똑같은 에러로 죽네요.. 대체 문제가뭔지 감이 잡히질 않습니다.
ps : 소스넣을때 태그 어떻게 처리하나용 우.. 소스가 짤리네용
malloc()이나 free() 내부에서 문제가 일어날 것 같지는 않습니다.
사실 malloc()이나 free()의 thread-safe 여부는 사용하시는 컴파일러와 라이브러리에 달려 있습니다.
하지만 지금 실제로 사용되는 환경에서 malloc()이나 free()가 thread-safe하지 않다는 것은
좀 상상하기 어려울 것 같습니다.
Free()에 들어가는 변수들이 전부 local에서 할당되고 반환된다면 racing condition은 생각할 필요가
없습니다. 하지만 할당되는 위치가 global이거나 다른 thread에서 사용한다면 물론 문제가 될 수 있겠지요.
음, 이건 너무나 원칙적인 이야기입니다만, 소스코드가 없으니 이런저런 상상을 해 볼 수밖에요.
혹시 Free()에서 NULL을 할당해주는 것을 과신하신 부분이 있지 않을까 싶기도 합니다.
예컨대...
char * cp1 = (char *)malloc( sizeof(char) * 16 );
char * cp2 = cp1;
Free( cp2 );
코드가 이런 식으로 작성되어 있는 경우, Free()를 실행한 후 cp2는 NULL이겠지만
cp1은 원래 값 그대로일 겁니다. 여기서 cp1을 또다시 Free()하는 경우 double free가 되겠지요.
(역시나 상상일 뿐입니다만, 예를 들어서 그렇다는 겁니다.)
참고로, 바로 위에 올려주신 코드는 잘 안 보이는군요. ^_^
pthread를 사용하신다면 HAVE_PTHREAD_H을 1로 선언해야합니다.
이미 오래전 글입니다만, 제가 확인한 내용을 써봅니다. 다음 definition을 선언해야 합니다.
memwatch.c
...
#define HAVE_PTHREAD_H 1 // 이 라인을 추가해서 사용하시면 됩니다.
...
#if defined(MW_PTHREADS) || defined(HAVE_PTHREAD_H)
#define MW_HAVE_MUTEX 1
#include
#endif
이를 사용하지 않으면, lock을 사용하지 않기에 memwatch가 사용하는 내부 구조체가 multi-thread환경에서 깨져버립니다.
그래서 abort가 발생하는 거구요.
그럼 비슷한 문제를 겪을 분들에게 도움이 됐으면 합니다.
댓글 달기