2014-01-24 1 views
2

다음은 내 상황에 대한 설명입니다. 우리 제품에서 버그를 처리해야합니다. 스레드는 joinable으로 생성되고 작업을 완료해야하며 아무도 그 스레드에 대해 pthread_join()을 호출하지 않습니다. 그래서 스레드 (기본적으로) 조인 속성으로 생성 및 종료하기 전에 다음 코드를 호출된다pthread_detach()는 64 비트 Linux에서 SIGSEGV를 발생시킵니다

{ pthread_detach(pthread_self()); pthread_exit(NULL); } 

그것은 내가 만난 모든 32 비트 리눅스 배포판에 매력처럼 작동하지만 64 비트 배포판에 SIGSEGV 원인 (우분투 13.04 x86_64 및 데비안). 나는 슬랙웨어로 시도하지 않았다. 여기에 핵심입니다 :이 버그를 수정하는 방법을 알아 냈

Core was generated by `IsaVM -s=1 -PrjPath="/home/taf/Linux_Fov_540148/Cmds" -stgMode=1 -PR -Failover'. 
Program terminated with signal 11, Segmentation fault. 
#0 0x00007f5911a7c009 in pthread_detach() from /lib/x86_64-linux-gnu/libpthread.so.0 
(gdb) bt 
#0 0x00007f5911a7c009 in pthread_detach() from /lib/x86_64-linux-gnu/libpthread.so.0 
#1 0x000000000041310d in _kerCltDownloadThr (StartParams=0x6bfce0 <RESFOV>) at ./dker0clt.c:1258 
#2 0x00007f5911a7ae9a in start_thread() from /lib/x86_64-linux-gnu/libpthread.so.0 
#3 0x00007f591159f3fd in clone() from /lib/x86_64-linux-gnu/libc.so.6 
#4 0x0000000000000000 in ??() 

-가 생성되기 전에 스레드가 나는 설정 CREATE_DETACHABLE 속성 (pthread_attr_setdetachstate()와)과 예상대로 작동합니다.

하지만 내 질문 -이 코드를 호출하는 것이 범죄입니까?

{ pthread_detach(pthread_self()); pthread_exit(NULL); } 

pthread_detach() 비동기 호출 후에 무언가를 수행하고 그 pthread_exit()을 문제를 가져 오는 원인은? 그러나 충돌 지점은 pthread_detach()이 아니며 pthread_exit()입니다! 나는이 충돌에 대한 이유를 완전히 이해하지 못한다! 왜 32 비트에서 작동합니까? pthread 구현 어딘가에 경쟁 조건이 있습니까?

pthread_join()이 스레드에 대해 호출되지 않았습니다.

미리 아이디어를 제공해 주셔서 감사합니다.

답변

0

필자는 훌륭한 @MaximYegorushkin에서 제공하는 접근 방식으로 연구를 마쳤습니다. AddressSanitizer은 우리 제품에서 하나의 버퍼 오버플로를 보여 주지만 내 문제와 관련이 없습니다 (나중에 확실히 고치겠습니다. 버그를 찾기 위해 현명한 도구를 사용하는 것이 좋습니다).따라서 모든 필요한 pthread_xxx 함수를 LD_PRELOAD 메서드로 재정의하기로 결정했습니다. 예상대로 내 라이브러리 작동하는지 확인하는 간단한 테스트를 실행 :

[HACK] Loading pthread hack. 
Starting thread...! 
[HACK] pthread_create: thread=7FAC6C86D700 
Waiting for 2 seconds... 
[HACK] pthread_self: thread=7FAC6C86D700 
thread_func: thread id = 7FAC6C86D700 
Thread: sin(3.26) = -0.121109 
[HACK] pthread_self: thread=7FAC6C86D700 
[HACK] pthread_detach: thread=7FAC6C86D700 
Terminating... 

모든 문자열이 에서 시작 [해킹]은 내 threadhack.so 라이브러리에 의해 생성된다.

코드가 실행 : { pthread_detach(pthread_self()); pthread_exit(NULL); }

디버그 추적 :

[HACK] pthread_create: thread=7F403251CB00 
..... 
[HACK] pthread_self: thread=7F403251CB00 
[HACK] pthread_detach: thread=3251CB00  

그래서 우리는 pthread_self 좋은 스레드 ID를 반환하는 것을 볼 은 그 때 나는이 라이브러리 문제가 정확히 어디에 그것이 나 포인트 내 프로젝트를 실행 하지만 pthread_detach은 이미 맹 글링 처리를 마쳤습니다 (32 비트로 자르기). 어떻게 될 수 있니? 나는 참고로 내 프로젝트에 대한 내 간단한 작업 테스트 응용 프로그램 모두에 대한 어셈블러 코드를 생성 :

참조 응용 프로그램 :

call pthread_self 
movq %rax, %rdi 
call pthread_detach 
movl $0, %edi 
call pthread_exit 

그래서 우리는 movq 명령은 64 비트 스레드 ID를 복사하는 데 사용되는 것을 여기에서 볼 (movq %rax, %rdi). OK, 내 프로젝트에 대한 를 생성 무엇 GCC 확인 :

movl $0, %eax 
call pthread_self 
movl %eax, %edi 
movl $0, %eax 
call pthread_detach 
movl $0, %edi 
movl $0, %eax 
call pthread_exit 

WOA를! 우리는 두 개의 movl 명령어 (32 비트)를 가지고 있고, 하나는 최하위 32 비트 (movl %eax, %edi)를 복사하고 가장 중요한 부분 대신에 항상 0을 넣습니다! (movl $0, %eax). 이게 왜 이드가 엉망이 된지에 대한 이유입니다. 왜 코드가 다른지 잘 모르겠다. 컴파일 플래그는 동일하다. 이 버그를 보았습니다 GCC 4.7GCC 4.8 (Ubuntu 13.10 x86_64의 최신 패키지)에이 버그가 있습니다.

적어도 지금 나는 무엇이 hapenning하는지 본다. @Maxim과 훌륭한 도구 덕택입니다. 나는 새로운 것을 다시 배웠다.

P. 버그 리포트를 GCC 팀에 제출하는 방법을 모르겠습니다. 나는 작은 간단한 응용 프로그램에서 문제를 재현 할 수 없으며 독점 ​​소프트웨어이고 배포하지 않기 위해 NDA - ed 때문에 내 프로젝트를 넘겨 줄 수 없습니다.

+0

문제가 gcc에있는 것으로 의심됩니다. 소스 코드를 게시하십시오. –

+0

나는 이것을 할 수 없다, 나는 NDA하에있다. 아마도 pthread_self()가 호출 된 문제 함수 만 게시 할 수 있습니다. 여기에 비공개 메시지를 보낼 수있는 방법이 있습니까? –

+0

당신이 분해 한 기능. 하지만 난 당신이 자신의 대답을 받아 볼 수 있도록, 당신은 문제를 해결해야하고 더 이상 도움을 필요로하지 말아야합니다) –

1

스레드 분리 자체가 옳지 않다고 생각합니다. 필요한 경우 분리 된 스레드를 작성할 수있는 pthread_create()을 호출 한 스레드는 일반적으로 책임이 있습니다.

스레드가 이미 분리되었을 수 있습니다. 이미 분리 된 스레드를 분리하려고 시도하면 지정되지 않은 동작이 발생합니다.

내 최고 야생 추측은 다음과 같습니다

  1. 스레드는 한 번 이상 분리됩니다. 빠른 검사로 pthread_detach에있는 중단 점을 gdb에 설정하면 중복 스레드 ID가이 함수에서 전달되는지 여부를 확인할 수 있습니다. gdb에서 응용 프로그램을 실행하기 어려운 경우 pthread_createpthread_detach을 덮어 쓰고 이중 분리를 감지하는 스레드 ID를 추적하는 것이 좋습니다. http://hackerboss.com/overriding-system-functions-for-fun-and-profit/

  2. 메모리 손상을 참조하십시오. valgrind은 응용 프로그램을 실행할 수있는 경우 메모리 손상을 감지하는 데 도움이 될 수 있습니다. 또는 gcc을 사용하는 경우 -fstack-protector-all, -fsanitize=address, -fsanitize=thread으로 컴파일하여 런타임 오류 검사로 응용 프로그램을 계측 해보십시오. clang 컴파일러에는 이러한 오류를 감지하는 옵션 배열도 있습니다. http://clang.llvm.org/docs/index.html에있는 살균제를 참조하십시오.

+0

pthread_detach()); –

+0

@OlegOsovitskiy 그래도 좋은 디자인 예는 아니지만. –

+0

정확히 똑같은 일을하는 작은 프로그램을 만들려고 할 때 self + exit가 즉시 분리됩니다.이 버그를 더 이상 재현 할 수 없습니다. 예상대로 작동합니다.큰 프로젝트에서만 발생합니다. –

0

제 생각에는 pthread_detach (pthread_self())를 호출하는 코드에서 pthread_detach 또는 pthread_self에 대한 프로토 타입이 없다는 것입니다. 프로토 타입이 없으면 컴파일러는 인수가 int (pthread_detach)이거나 함수가 int (pthread_self)를 반환한다고 가정합니다.

더 깊이 생각해 보았지만, pthread_self가 undefined (int 반환)이거나 int를 반환하는 것으로 잘못 정의 된 것으로 의심됩니다. 그런 다음 컴파일러는이 값을 32 비트의 선행 비트를 더하여 64 비트 정수로 올바르게 확장합니다. 다음 명령문은 호출 스레드 분리 : pthread_detach을 (pthread_self 수동 [링크] (http://man7.org/linux/man-pages/man3/pthread_detach.3.html)의 예 절에서 말합니다

+1

질문을 잘못 읽었거나 알 수없는 주제에 대해서만 알지 못한다면 그 원인을 추측 할 수있는 해결책을 추가하십시오 나는 가능한 이야기입니다. –