2016-10-26 2 views
2

모듈을 완전히 단위 테스트 할 수 있도록 pthread_create를 스텁 아웃하려고합니다. 테스트 프레임 워크 내에서 함수 포인터가 호출되면 분할 오류가 발생합니다. 'gdb'를 사용하여 프로그램을 디버깅하면 함수 포인터를 직접 호출 할 수 있으며 제대로 작동합니다.pthread_create에 대한 함수 포인터를 사용하면 segfault가 발생합니다

저는 CppUTest를 단위 테스트 프레임 워크로 사용하고 gcc를 사용하여 객체 파일을 컴파일했습니다.

이 함수는 pthread_create에 함수 포인터를 사용하기 위해 프로덕션 코드에서 변경되었습니다. 따라서이 함수는 일반적으로 확실합니다.

> Starting program: 
> /home/lucid/depot/torr_linux_common_dev/main/src/Utilities/tests/testRunner 
> [Thread debugging using libthread_db enabled] Using host libthread_db 
> library "/lib/i386-linux-gnu/libthread_db.so.1". 
> 
> Program received signal SIGSEGV, Segmentation fault. 0x080660c4 in 
> sys_pthreads_create() (gdb) backtrace 
> #0 0x080660c4 in sys_pthreads_create() 
> #1 0x08049ee4 in th_start_thread_name (thread=0x8049e64 <TestThread>, arg=0x0, opts=0x0, name=0x0) at thr.c:177 
> #2 0x08049e47 in test_ThreadTestGroup_ThreadCreateUnnamed_wrapper_c() at thr_test.c:66 
> #3 0x08049223 in TEST_ThreadTestGroup_ThreadCreateUnnamed_Test::testBody 
> (this=0x806cc90) at testRunner.c:21 
> #4 0x0805576a in PlatformSpecificSetJmpImplementation() 
> #5 0x08053ab7 in Utest::run()() 
> #6 0x080550d5 in UtestShell::runOneTestInCurrentProcess(TestPlugin*, TestResult&)() 
> #7 0x08053645 in helperDoRunOneTestInCurrentProcess() 
> #8 0x0805576a in PlatformSpecificSetJmpImplementation() 
> #9 0x08053b8f in UtestShell::runOneTest(TestPlugin*, TestResult&)() 
> #10 0x080530ef in TestRegistry::runAllTests(TestResult&)() 
> #11 0x0804a3ef in CommandLineTestRunner::runAllTests()() 
> #12 0x0804a4e9 in CommandLineTestRunner::runAllTestsMain()() 
> #13 0x0804a628 in CommandLineTestRunner::RunAllTests(int, char const**)() 
> #14 0x08049246 in main (argc=1, argv=0xbffff244) at testRunner.c:25 

나는 그것이 내가 테스트입니다

(gdb) p (*sys_pthreads_create)(&thr, 0, thread, arg) 
[New Thread 0xb7c01b40 (LWP 17717)] 
$4 = 0 

기능을 작동 GDB 내에서 함수 포인터를 호출하는 경우 GDB에서

스택 추적

#include <pthread.h> 
#include "mypthreads.h" 
long th_start_thread_name(TH_THREAD_FUNC thread, void *arg, th_opts *opts, const char* name) 
{ 
    pthread_t thr; 
    int ret, sret; 
    //pthread_create(opts ? &opts->thr : &thr, NULL, thread, arg); 
    ret = (*sys_pthreads_create)(opts ? &opts->thr : &thr, 0, thread, arg); 
    if (ret == 0 && name != NULL) 
    { 
     extern int pthread_setname_np(pthread_t thr, const char *name); /* Fix warning from missing prototype. */ 

     sret = pthread_setname_np(opts ? opts->thr : thr, name); 
     /* pthreads says that thread names must not exceed 16, including NULL. */ 
     if (sret != 0 && strlen(name) > 15) 
     { 
      ret = -1; 
     } 
    } 
    return (long)ret; 
} 

mypthreads.h

extern int (*sys_pthreads_create(pthread_t *, const pthread_attr_t *, 
          void *(*) (void*), void *)); 

mypthreads.c

#include <stdio.h> 
#include <pthread.h> 

int my_pthread_create(pthread_t *thread, const pthread_attr_t *attr, 
          void *(*start_routine) (void *), void *arg) 
{ 
    printf("Did you get the messsage?"); 
    return pthread_create(thread, attr, start_routine, arg); 
} 


int (*sys_pthreads_create)(pthread_t *thread, const pthread_attr_t *attr, 
          void *(*start_routine) (void *), void *arg) = my_pthread_create; 

편집 : 함수 포인터를 호출하고 성공 GDB에서 추가 출력. 인해 잘못된 괄호에

extern int (*sys_pthreads_create(pthread_t *, const pthread_attr_t *, void *(*) (void*), void *)); 

,이 기호의 유형 int에 대한 포인터를 반환하는 함수가,하지만 실제 sys_pthreads_create 목적 :

+0

디버거에 따라 'my_pthread_create'를 입력하지 않았 음을 확인하십시오. 어쩌면 당신은 어떻게 든 당신의 함수 포인터를 숨기고 당신이 호출하는 복사본에 쓰레기를 가지고 있을지도 모른다. –

+1

디버그 정보를 사용하여 코드를 작성하고 최적화가 비활성화되어있는 것이 좋습니다. 그러면 Gdb가 오류에 대한 자세한 정보를 제공 할 수 있습니다. 또한 gdb가 segfault를 잡은 후에도 여전히 스택을 검사 할 수 있습니다 - 디버그 정보도 도움이 될 것입니다. –

+0

@Jens Gusted "예, my_pthread_create가 호출 된 적이 없다는 것을 알고 있습니다."p (* sys_pthreads_create) (& thr, 0, thread, arg) "를 gdb에서 실행하면 함수 포인터가 올바르게 호출되고 gdb는 스레드 –

답변

3

문제는 mypthreads.h에 선언이 잘못된 유형을 가지고 있다는 것입니다 함수에 대한 포인터입니다.

ret = (*sys_pthreads_create)(opts ? &opts->thr : &thr, 0, thread, arg); 

sys_pthreads_create

암시 그것의 주소를 복용하여 함수에 대한 포인터로 변환되고, 그 주소를 역 참조와 호출을 :

당신이 호출 할 때 것을 의미한다. 하지만 실제로 함수의 주소가 아닙니다. 함수 포인터에 대한 주소입니다! 따라서 코드 포인터로 함수 포인터를 실행하려고 할 때 (또는 실행 불가능한 매핑으로 인해 충돌이 발생할 때) sys_pthreads_create이있는 데이터 세그먼트로 호출이 이동하고 충돌합니다.

이 gdb를 출력에서이에 대한 단서는 다음과 같습니다

#0 0x080660c4 in sys_pthreads_create() 

그것은 sys_pthreads_create 내에서 실행 있다고 말한다 - 그러나 sys_pthreads_create 변수가 아닌 기능입니다.

당신이 mypthreads.c에서 <mypthreads.h>을 포함했다면 sys_pthreads_create에 대한 충돌 유형 (소스 파일의 개체를 선언하는 헤더 파일을 항상 포함해야한다 그 이유는 그것을 볼 수 있었다 때문에 컴파일러는 사용자를 위해이 진단 한 것이라고 그러한 객체들을 정의한다.)

물론 올바른 선언은 mypthreads.c 일치 하나입니다

extern int (*sys_pthreads_create)(pthread_t *thread, const pthread_attr_t *attr, 
         void *(*start_routine) (void *), void *arg); 

gdb이 성공적으로 GDB가를 결정하기 위해 디버깅 정보를 저장 형식 정보를 사용했다 함수 포인터를 호출 할 수 있었다하는 이유 유형은 sys_pthreads_create이고 헤더 파일의 가짜 정보는 아닙니다.

관련 문제