C - double free or corruption

#1
Meepmeep.

Ich hab ein Problem beim erstellen einer verketteten Liste für einen Prozess-Scheduler.
Ich versuche per folgender Methode den Speicher für einen struct freizugeben.

Code:
void mtDelThread(ThreadCB* tcb)
{
    free((void*)(tcb->stack));
    free(tcb);
}
Den struct hier:

Code:
typedef struct ThreadCB {
    unsigned      tID;              // thread-ID
    unsigned      tPrio;            // thread priority
    unsigned      readyTime;        // time, when a a waiting thread
                                    // can be activated, in clock ticks

    TMethod       startMethod;      // pointer to the user thread metcbod
    void          *arg;             // poniter to the argument of the metcbod

    unsigned long stackpointer;     // current stackpointer of the thread
    unsigned long stack;            // bottom of stack

    int          firstCall;         // thread runs for the first time
} ThreadCB;
Nun die Funktion mtDelThread existiert bereits in der Vorgabe, dürfte also korrekt funktionieren.

Beim Aufruf dieser Funktion aborted g++ bei folgender Zeile:
Code:
free(tcb);
Die vorhergehende Zeile funktioniert wie erwartet:
Code:
free((void*)(tcb->stack));
Ein Backtrace der Fehlermeldung hier:
Code:
*** glibc detected *** ./test1: double free or corruption (fasttop): 0x09011c68 ***
======= Backtrace: =========
/lib/libc.so.6(+0x6c501)[0xb74b9501]
/lib/libc.so.6(+0x6dd70)[0xb74bad70]
/lib/libc.so.6(cfree+0x6d)[0xb74bde5d]
./test1[0x8048cda]
./test1[0x80488d9]
/lib/libc.so.6(__libc_start_main+0xe7)[0xb7463ce7]
./test1[0x80485e1]
Und die vollständige Ausgabe inkl. Memory-Map
Code:
*** glibc detected *** ./test1: double free or corruption (fasttop): 0x09011c68 ***
======= Backtrace: =========
/lib/libc.so.6(+0x6c501)[0xb74b9501]
/lib/libc.so.6(+0x6dd70)[0xb74bad70]
/lib/libc.so.6(cfree+0x6d)[0xb74bde5d]
./test1[0x8048cda]
./test1[0x80488d9]
/lib/libc.so.6(__libc_start_main+0xe7)[0xb7463ce7]
./test1[0x80485e1]
======= Memory map: ========
08048000-0804a000 r-xp 00000000 08:01 5642857    /home/sheeep/ZHAW/04/BESY/01/Intro/listen/test1
0804a000-0804b000 r--p 00001000 08:01 5642857    /home/sheeep/ZHAW/04/BESY/01/Intro/listen/test1
0804b000-0804c000 rw-p 00002000 08:01 5642857    /home/sheeep/ZHAW/04/BESY/01/Intro/listen/test1
09011000-09032000 rw-p 00000000 00:00 0          [heap]
b7300000-b7321000 rw-p 00000000 00:00 0 
b7321000-b7400000 ---p 00000000 00:00 0 
b744b000-b744d000 rw-p 00000000 00:00 0 
b744d000-b75a4000 r-xp 00000000 08:01 5505747    /lib/libc-2.12.1.so
b75a4000-b75a6000 r--p 00157000 08:01 5505747    /lib/libc-2.12.1.so
b75a6000-b75a7000 rw-p 00159000 08:01 5505747    /lib/libc-2.12.1.so
b75a7000-b75aa000 rw-p 00000000 00:00 0 
b75aa000-b75c4000 r-xp 00000000 08:01 5505103    /lib/libgcc_s.so.1
b75c4000-b75c5000 r--p 00019000 08:01 5505103    /lib/libgcc_s.so.1
b75c5000-b75c6000 rw-p 0001a000 08:01 5505103    /lib/libgcc_s.so.1
b75c6000-b75c7000 rw-p 00000000 00:00 0 
b75c7000-b75eb000 r-xp 00000000 08:01 5505751    /lib/libm-2.12.1.so
b75eb000-b75ec000 r--p 00023000 08:01 5505751    /lib/libm-2.12.1.so
b75ec000-b75ed000 rw-p 00024000 08:01 5505751    /lib/libm-2.12.1.so
b75ed000-b76cc000 r-xp 00000000 08:01 1576533    /usr/lib/libstdc++.so.6.0.14
b76cc000-b76d0000 r--p 000de000 08:01 1576533    /usr/lib/libstdc++.so.6.0.14
b76d0000-b76d1000 rw-p 000e2000 08:01 1576533    /usr/lib/libstdc++.so.6.0.14
b76d1000-b76d8000 rw-p 00000000 00:00 0 
b76ec000-b76f0000 rw-p 00000000 00:00 0 
b76f0000-b76f1000 r-xp 00000000 00:00 0          [vdso]
b76f1000-b770d000 r-xp 00000000 08:01 5505744    /lib/ld-2.12.1.so
b770d000-b770e000 r--p 0001b000 08:01 5505744    /lib/ld-2.12.1.so
b770e000-b770f000 rw-p 0001c000 08:01 5505744    /lib/ld-2.12.1.so
bf9bb000-bf9dc000 rw-p 00000000 00:00 0          [stack]
Aborted

Nun meine Frage. Was genau bedeutet diese Fehlermeldung? Wie lässt sich das Verhalten erklären, vor allem im Bezug darauf, dass er erst beim deallozieren des eigentlichen ThreadCB probleme macht, nicht jedoch davor?
 
#2
Die Zeile free((void*)(tcb->stack)); ist quatsch, da die Variable 'stack' eine Primitive ist. (unsigned long stack;)

Du musst unterscheiden zwischen Objekten und Primitiven. Eine Instanz einer Struktur oder einer Klasse ist ein Objekt, welches du ggf. dynamisch allokierst mit *alloc bzw new. Diese Objekte - falls dynamisch allokiert - musst du dann auch zu einem gewissen Zeitpunkt wieder freigeben (free bzw delete).
Bei Primitiven ist das anders, diese Variablen werden stets vollständig kopiert.

/€1:
Oh, jetzt seh ich erst was da geschieht ... du speicherst in der Variablen 'stack' eine Adresse ... Das lässt das ganze dann natürlich anders aussehen. Trotzdem ist das etwas verwirrend, warum die Adresse in einen ulong speichern, wenn du einfach einen Pointer anlegen kannst?
An dieser Stelle solltest du dann darauf achten, dass tcb->stack nicht auf tcb zeigt.
 
Zuletzt bearbeitet:
Oben