2016-10-26 9 views
2

Я пытаюсь заглушить pthread_create, чтобы иметь возможность полностью тестировать модуль. Когда вызывается указатель функции из тестовой среды, возникает ошибка сегментации. Если я отлаживаю программу с помощью «gdb», я могу напрямую вызвать указатель на функцию, и она работает правильно.Использование указателя функции для pthread_create вызывает segfault

Я использую CppUTest в качестве модульной тестовой среды и скомпилировал мои объектные файлы с помощью gcc.

Эта функция работала в производственном коде, прежде чем изменять ее, чтобы использовать указатель функции для pthread_create, поэтому я уверен в функции в целом.

Трассировка стека из GDB

> 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 работает

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

Функция Я тестирование

#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; 

Edit: Добавлен вывод из GDB, когда я звоню указатель на функцию и преуспевает.

+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 имеет неправильный тип:

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

Из-за неуместные скобки, типа этого символа является функцией, которая возвращает указатель на int, но ваш фактический sys_pthreads_create объекта является указателем на функцию.

Это означает, что при вызове:

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.h> в mypthreads.c, потому что конфликтные ситуации для 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, а не фиктивная информация из файла заголовка.