2016-10-26 3 views
2

Ich versuche, pthread_create auszugeben, um ein Modul komplett Unit-Test zu testen. Wenn der Funktionszeiger innerhalb des Test-Frameworks aufgerufen wird, tritt ein Segmentierungsfehler auf. Wenn ich das Programm mit 'gdb' debugge, kann ich den Funktionszeiger direkt aufrufen und es funktioniert korrekt.Die Verwendung eines Funktionszeigers auf pthread_create führt zu segfault

Ich verwende CppUTest als Unit-Test-Framework und habe meine Objektdateien mit gcc kompiliert.

Diese Funktion hat im Produktionscode gearbeitet, bevor sie geändert wurde, um einen Funktionszeiger für pthread_create zu verwenden, also bin ich zuversichtlich in die Funktion im Allgemeinen.

Stack-Trace von 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 

Wenn ich den Funktionszeiger aufrufen aus gdb funktioniert es

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

Funktion I-Tests am

#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: Hinzugefügt Ausgabe von gdb, wenn ich den Funktionszeiger aufrufen und es gelingt.

+0

Beachten Sie, dass Sie laut Ihrem Debugger nicht einmal 'my_pthread_create' eingegeben haben. Vielleicht schirmen Sie Ihren Funktionszeiger irgendwie ab und haben in der Kopie, die Sie aufrufen, Müll. –

+1

Erwägen Sie, Ihren Code mit Debug-Informationen zu erstellen und möglicherweise mit deaktivierter Optimierung. Gdb sollte dann in der Lage sein, Ihnen mehr Informationen über den Fehler zu geben. Beachten Sie auch, dass Sie den Stack immer noch untersuchen können, nachdem gdb den segfault abgefangen hat - die Debug-Informationen helfen auch dabei. –

+0

@Jens Gusted "Ja, mir ist bewusst, dass my_pthread_create nie aufgerufen wurde. Wenn ich" p (* sys_pthreads_create) (& thr, 0, thread, arg) "innerhalb von gdb ausführe, wird der Funktionszeiger korrekt aufgerufen und gdb zeigt den Thread an –

Antwort

3

Das Problem ist, dass Ihre Erklärung in mypthreads.h die falsche Art hat:

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

Durch ein verlegtes Klammern, die Art dieses Symbols ist eine Funktion, die einen Zeiger auf int zurück, aber Ihr tatsächliches sys_pthreads_create Objekt ist ein Zeiger auf eine Funktion.

Dies bedeutet, dass, wenn Sie anrufen:

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

sys_pthreads_create auf einen Zeiger auf eine Funktion, indem sie implizit das Ermitteln der Adresse es umgewandelt wird, dann wird diese Adresse dereferenziert wird und aufgerufen. Aber das ist nicht wirklich die Adresse einer Funktion - es ist die Adresse eines Zeigers auf eine Funktion! Der Aufruf springt also in das Datensegment, in dem sys_pthreads_create lebt und abstürzt, wenn es versucht, den Funktionszeiger als Code auszuführen (oder aufgrund eines nicht ausführbaren Mappings abstürzt).

Es gibt einen Hinweis auf das in der GDB Ausgabe:

#0 0x080660c4 in sys_pthreads_create() 

Er sagt, dass es innerhalb sys_pthreads_create ist die Ausführung - aber sys_pthreads_create ist eine Variable, keine Funktion.

Der Compiler würde dies für Sie haben diagnostiziert, wenn Sie <mypthreads.h> in mypthreads.c aufgenommen hatte, weil die Konflikttypen für sys_pthreads_create haben, um es sichtbar gewesen wäre (das ist, warum Sie immer die Header-Datei enthalten sollte, die Objekte in den Quelldateien erklärt, dass Definieren Sie diese Objekte).

Die richtige Erklärung ist natürlich derjenige, der mypthreads.c Spiele:

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

Der Grund, dass gdb der Lage war, den Funktionszeiger erfolgreich zu rufen, dass gdb die Typinformationen verwendet in der Debug-Informationen gespeichert die bestimmen Art von sys_pthreads_create, nicht die falschen Informationen aus der Header-Datei.

Verwandte Themen