Malloc segmentation fault
Hier ist das Stück code in dem "segmentation fault" Auftritt (perror wird nicht genannt):
job = malloc(sizeof(task_t));
if(job == NULL)
perror("malloc");
Um genauer zu sein, gdb sagt, dass die segfault
geschieht innerhalb eines __int_malloc
- call, das ist eine sub-routine Aufruf von malloc
.
Da die malloc-Funktion aufgerufen wird, parallel zu anderen threads, anfangs dachte ich, es könnte das problem sein.
Ich war mit version 2.19 glibc.
Datenstrukturen:
typedef struct rv_thread thread_wrapper_t;
typedef struct future
{
pthread_cond_t wait;
pthread_mutex_t mutex;
long completed;
} future_t;
typedef struct task
{
future_t * f;
void * data;
void *
(*fun)(thread_wrapper_t *, void *);
} task_t;
typedef struct
{
queue_t * queue;
} pool_worker_t;
typedef struct
{
task_t * t;
} sfuture_t;
struct rv_thread
{
pool_worker_t * pool;
};
Nun die künftige Umsetzung:
future_t *
create_future()
{
future_t * new_f = malloc(sizeof(future_t));
if(new_f == NULL)
perror("malloc");
new_f->completed = 0;
pthread_mutex_init(&(new_f->mutex), NULL);
pthread_cond_init(&(new_f->wait), NULL);
return new_f;
}
int
wait_future(future_t * f)
{
pthread_mutex_lock(&(f->mutex));
while (!f->completed)
{
pthread_cond_wait(&(f->wait),&(f->mutex));
}
pthread_mutex_unlock(&(f->mutex));
return 0;
}
void
complete(future_t * f)
{
pthread_mutex_lock(&(f->mutex));
f->completed = 1;
pthread_mutex_unlock(&(f->mutex));
pthread_cond_broadcast(&(f->wait));
}
Den thread-pool selbst:
pool_worker_t *
create_work_pool(int threads)
{
pool_worker_t * new_p = malloc(sizeof(pool_worker_t));
if(new_p == NULL)
perror("malloc");
threads = 1;
new_p->queue = create_queue();
int i;
for (i = 0; i < threads; i++){
thread_wrapper_t * w = malloc(sizeof(thread_wrapper_t));
if(w == NULL)
perror("malloc");
w->pool = new_p;
pthread_t n;
pthread_create(&n, NULL, work, w);
}
return new_p;
}
task_t *
try_get_new_task(thread_wrapper_t * thr)
{
task_t * t = NULL;
try_dequeue(thr->pool->queue, t);
return t;
}
void
submit_job(pool_worker_t * p, task_t * t)
{
enqueue(p->queue, t);
}
void *
work(void * data)
{
thread_wrapper_t * thr = (thread_wrapper_t *) data;
while (1){
task_t * t = NULL;
while ((t = (task_t *) try_get_new_task(thr)) == NULL);
future_t * f = t->f;
(*(t->fun))(thr,t->data);
complete(f);
}
pthread_exit(NULL);
}
Und schließlich die Aufgabe.c:
pool_worker_t *
create_tpool()
{
return (create_work_pool(8));
}
sfuture_t *
async(pool_worker_t * p, thread_wrapper_t * thr, void *
(*fun)(thread_wrapper_t *, void *), void * data)
{
task_t * job = NULL;
job = malloc(sizeof(task_t));
if(job == NULL)
perror("malloc");
job->data = data;
job->fun = fun;
job->f = create_future();
submit_job(p, job);
sfuture_t * new_t = malloc(sizeof(sfuture_t));
if(new_t == NULL)
perror("malloc");
new_t->t = job;
return (new_t);
}
void
mywait(thread_wrapper_t * thr, sfuture_t * sf)
{
if (sf == NULL)
return;
if (thr != NULL)
{
while (!sf->t->f->completed)
{
task_t * t_n = try_get_new_task(thr);
if (t_n != NULL)
{
future_t * f = t_n->f;
(*(t_n->fun))(thr,t_n->data);
complete(f);
}
}
return;
}
wait_future(sf->t->f);
return ;
}
Den Warteschlange ist die lfds lock-free queue.
#define enqueue(q,t) { \
if(!lfds611_queue_enqueue(q->lq, t)) \
{ \
lfds611_queue_guaranteed_enqueue(q->lq, t); \
} \
}
#define try_dequeue(q,t) { \
lfds611_queue_dequeue(q->lq, &t); \
}
Das problem passiert immer dann, wenn die Anzahl der Aufrufe async ist sehr hoch.
Valgrind-Ausgabe:
Process terminating with default action of signal 11 (SIGSEGV)
==12022== Bad permissions for mapped region at address 0x5AF9FF8
==12022== at 0x4C28737: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
- Ist es möglich, etwas anderes vermasselt die Buchhaltung für
malloc
? - Es klingt wie Speicher beschädigt woanders.
- Es ist die einzige Erklärung, poste ich den ganzen code. (Es ist wirklich ein minimales Modell, mit memory leaks, etc.).
- "wenn nötig, ich kann hier den vollständigen source code" - ja, das ist wahrscheinlich das, was Sie tun SOLLTEN, denn das Stück code oben selbst kann nicht bedeuten, die Quelle der segfault.
- ok, fertig (dauerte einige Zeit damit, die 4 Felder überall, aber dann fand ich heraus, das mit Strg+k Abkürzung 🙂 )
- ist dieser code reicht? Da kann ich alle code, einschließlich der beispielsweise im Betrieb, und die Warteschlange, die ich verwende. Die Warteschlange, die ich benutze ist von lfds lib und das Beispiel ist eine einfache fibonaci, die spawns zwei Aufgaben und wartet, für Sie).
- Ich weiß nicht, was
try_deque
ist, aber es scheint, Sie sollten senden einen Zeiger an einen Zeigertry_dequeue(thr->pool->queue, &t);
wie diese. - die try_dequeue gibt eine Aufgabe. der code, den ich gesetzt habe, funktioniert, für kleine Berechnungen, aber für die großen ist, wo die Probleme beginnen
- Es nichts zurückgibt, ist es wohl gemeint-zu-Punkt
t
einer Aufgabe. Es können nicht tun, wenn Sie Sie senden eine Kopie des Zeigers. - Ich habe aktualisiert die post, um Sie zu beantworten. Ich weiß, es ist komisch, der Weg im Moment, es zu tun.
- in das makro, wo ich die &t, obwohl ich nicht sollte)
- Okay, ich sehe.
- Andere erwähnt haben heap-Beschädigung, - das heißt, schreiben-vorbei-Ende Fehler, etc. Sie könnten in Erwägung ziehen, die glibc-Einrichtungen wie heap-überprüfung mit
mcheck / mprobe
. - Danke, ich werde versuchen, dass.
- Keine chance, das Programm läuft unter valgrind? Wenn der Speicher Korruption vorgeht, valgrind könnte in der Lage sein, Ihnen zu zeigen, wo und Wann.
- Sorry, ich habe die Ausgabe in der questoin.
- Könnte das ein bug in malloc?
- Ich denke nicht, aber es ist wahrscheinlicher als ein Fehler in malloc
- Sorry, nur um sicher sein, dass wir testen, der gleiche code.. kann man kommentieren, enqueue(p->queue, t); try_dequeue(thr->pool>queue, t); e new_p->queue = create_queue() ? Tut es immer noch crash?
- ich kann nicht coment es aus, ohne zu ändern das Ziel dieses Programms. Aber wenn Sie wollen, kann ich Ihnen den vollständigen Quellcode, einschließlich der wichtigsten, das Makefile, und so weiter, so können Sie vollständig zu testen. (Alles ist hier einfach viel zu viel, und ich würde wahrscheinlich vorstellen viel Verwirrung ich wer sonst liest diesen post). Was die enqueue-und try_dequeue tun ist, setzen Sie eine Aufgabe in die Globale Warteschlange des Pools und de try_dequeue bekommt eine Aufgabe aus der globalen Warteschlange des Pools.
- Ich wird vergangenen hier code für Sie vor. Dies versuchen.
- Ich klebte den code hier unten, versuchen Sie das zuerst, wenn es nicht hilft, kann ich Ihnen helfen, Ihren code Debuggen.
- Danke, aber das hilft mir nicht viel, da das problem nur Auftritt, nachdem eine Menge von anrufen, die an die malloc-Betrieb
- Ich sah ähnliches Problem bei Beendigung des Prozesses, wenn der main-thread ist schon fertig, aber einige worker-threads sind noch fortsetzen -, dass dies geschieht, weil der heap ist schon zerstört
Du musst angemeldet sein, um einen Kommentar abzugeben.
Einem SIGSEGV (segmentation fault) wird ausgelöst bei malloc ist in der Regel verursacht durch heap-Beschädigung. Heap-Beschädigung führt nicht zu einem "segmentation fault", so würden Sie sehen, dass nur, wenn malloc versucht, Zugang gibt.
Das problem ist, dass der code zur Erstellung des heap-Beschädigung, könnten in jedem Punkt noch weit entfernt, von wo der malloc aufgerufen wird.
Es ist in der Regel die next-block-pointer innerhalb der malloc, der geändert wird, durch Ihre heap-Beschädigung auf eine ungültige Adresse, so dass, wenn Sie rufen malloc einen ungültigen Zeiger wird dereferenziert, und Sie bekommen einen segmentation fault.
Denke ich, können Sie versuchen, Teile des Codes isoliert vom rest des Programms zu reduzieren, die Sichtbarkeit der Fehler.
Außerdem sehe ich, dass Sie nie frei die Erinnerung hier und da kann ein möglicher Speicherverlust.
Um zu überprüfen, einen Speicherverlust führen Sie den Befehl top
top -b -n 1
und prüfen:Habe ich herausgefunden, was das problem ist: ein stack-überlauf.
Lassen Sie mich zuerst erklären, warum der stack overflow tritt innerhalb malloc (das ist wahrscheinlich, warum Sie dies Lesen). Wenn mein Programm ausgeführt wurde, der stack-Größe, die immer größer wird jedes mal, wenn es gestartet ausführen (rekursiv) eine andere Aufgabe (aufgrund der Art hatte ich es programmiert). Aber für jeden dieser Zeit hatte ich zuweisen eine neue Aufgabe mit malloc. Jedoch malloc macht anderen sub-routine aufruft, die den stack vergrößern sogar mehr als einen einfachen Aufruf ausführen einer anderen Aufgabe. So, was passiert war, war, dass, auch wenn es kein malloc, ich würde ein stack-überlauf. Allerdings hatte ich da malloc, der moment der stack übergelaufen war malloc, bevor es überflutet einen weiteren rekursiven Aufruf.
Die Abbildung Balg zeigt, was passiert war:
Erste stack-Zustand:
stack während der malloc-Aufruf:
Dann der stack schrumpfte wieder, und mein code eingegeben ein neuer rekursiver Aufruf:
Dann aufgerufen malloc wieder in diesem neuen rekursiven Aufruf. Aber dieses mal ist es übergelaufen:
[Der rest der Antwort ist mehr konzentrierte sich herum, warum ich hatte dieses problem in meinem code im besonderen.]
In der Regel, wenn Computer-Fibonacci rekursiv, zum Beispiel, eine bestimmte Anzahl n, die stack-Größe wächst Linear mit dieser Zahl.
Aber in diesem Fall bin ich mit der Erstellung von Aufgaben unter Verwendung einer Warteschlange zu speichern, und abarbeiten der Warteschlange ein (fib) task zur Ausführung. Wenn Sie zeichnen Sie diese auf dem Papier, Sie werden sehen, dass die Anzahl der Aufgaben wächst exponentiell mit n -, statt Linear (beachten Sie auch, dass, wenn ich hatte einen stack zum speichern der Aufgaben, wie Sie erstellt wurden, die Anzahl der zugewiesenen Aufgaben sowie die stack-Größe würde nur wachsen Linear mit n. So was passiert, ist, dass der stack wächst exponentiell mit n, was zu einem stack-overflow... Jetzt kommt der Teil, warum dieser überlauf tritt innerhalb der Aufruf von malloc. Also im Grunde, wie ich oben erklärte, ist die stack-überlauf passiert im inneren der malloc-Aufruf, da war es, wo der Stapel war größte. Was geschah, war, dass der Stapel war fast explodiert, und da malloc-Aufrufe Funktionen drin, der stack wächst mehr als nur das aufrufen von mywait und fib.
Danke an Euch alle! Wenn es nicht deine Hilfe, ich wäre nicht in der Lage, um es herauszufinden!