Malloc segmentation fault
Voici le morceau de code dans lequel erreur de segmentation se produit (la perror n'est pas appelé):
job = malloc(sizeof(task_t));
if(job == NULL)
perror("malloc");
Pour être plus précis, gdb dit que le segfault
qui se passe à l'intérieur d'un __int_malloc
appel, qui est une sous-routine à l'appel lancé par malloc
.
Depuis le malloc fonction est appelée en parallèle avec d'autres threads, j'ai d'abord pensé qu'il pourrait être le problème.
J'ai été en utilisant la version 2.19 de la glibc.
Les structures de données:
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;
};
Aujourd'hui, l'avenir de mise en œuvre:
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));
}
Le pool de threads lui-même:
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);
}
Et enfin la tâche.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 ;
}
La file d'attente est les écrans de verrouillage sans file d'attente.
#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); \
}
Le problème se produit chaque fois que le nombre d'appels à async est très élevé.
Valgrind de sortie:
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)
malloc
?Cela ressemble à de la mémoire est corrompu quelque part d'autre.
C'est la seule explication, je vais poster tout le code. (C'est vraiment un modèle minimal, avec des fuites de mémoire, etc).
"si besoin, je peux mettre ici le code source complet" - oui, c'est probablement ce que vous DEVEZ faire, parce que le morceau de code ci-dessus par lui-même, ne peut signifier la source de l'erreur de segmentation.
Aucune chance de l'exécution du programme sous valgrind? Si de corruption de la mémoire qui se passe, valgrind pourrait être en mesure de vous montrer où et quand.
OriginalL'auteur guilhermemtr | 2014-02-26
Vous devez vous connecter pour publier un commentaire.
Un SIGSEGV (erreur de segmentation) est tir dans la fonction malloc est habituellement causée par la corruption de segment. La corruption de segment de ne pas provoquer une erreur de segmentation, de sorte que vous verrez que c'est seulement quand malloc tente d'accéder.
Le problème est que le code qui crée la corruption de segment pourrait être en tout point, même loin de l'endroit où le malloc est appelé.
C'est en général la prochaine pointeur de bloc à l'intérieur de la malloc qui est changée par votre corruption de segment de mémoire à une adresse non valide, de sorte que lorsque vous appelez la fonction malloc un pointeur non valide obtient déréférencé et vous obtenez une erreur de segmentation.
Je pense que vous pouvez tenter certaines parties de votre code, isolé du reste du programme pour réduire la visibilité de la bogue.
De plus je vois que vous n'avez jamais libérer de la mémoire, ici et là peut-être une possible fuite de mémoire.
Afin de vérifier une fuite de mémoire vous pouvez exécuter la commande top
top -b -n 1
et vérifier:a vous de voir si il ya une fuite de mémoire? Je ne vois pas gratuitement ici.... avez-vous libérer de la mémoire parfois?
Je vais courir dans un problème si je n'ai pas de mémoire libre, tôt ou tard... que ce programme n'alloue ici...
C'est juste un modèle minimal, dans la version originale, il n'a pas de fuites de mémoire. dans celui-ci, je voulais juste vérifier le pourquoi de l'erreur, en éliminant le plus de code possible. Donc, dans cette version, je veux seulement trouver le malloc problème.
Si vous suppose que c'est un malloc problème que vous devriez juste allouer et libérer (pour éviter de sortir de segment de mémoire) la mémoire tousands de temps (malloc ne connaissez pas votre structure), de sorte que vous n'avez pas besoin de la totalité du programme, mais cela est très peu probable que cela arrive @guilhermemtr
OriginalL'auteur Jekyll
J'ai compris ce que le problème est le suivant: un débordement de pile.
Tout d'abord, laissez-moi vous expliquer pourquoi le dépassement de pile se produit à l'intérieur de la fonction malloc (ce qui est probablement la raison pour laquelle vous lisez ceci). Quand mon programme a été exécuté, la taille de la pile a continué d'augmenter à chaque fois qu'il a commencé en cours d'exécution (de manière récursive) une autre tâche (en raison de la façon dont j'avais programmé). Mais à chaque fois, j'ai dû allouer une nouvelle tâche à l'aide de malloc. Cependant, la fonction malloc rend les autres sous-appels de routine, qui font de la pile d'augmenter sa taille encore plus qu'un simple appel pour exécuter une autre tâche. Donc, ce qui se produit est que, même si il n'y avait pas de malloc, je voudrais obtenir un débordement de pile. Cependant, parce que j'ai eu malloc, le moment de la pile a été débordé dans le malloc, avant qu'il débordait d'en faire un autre appel récursif.
L'illustration soufflet montre ce qui se passait:
Stack Initial de l'état:
de la pile au cours de malloc appel:
Ensuite la pile s'est de nouveau contractée, et mon code est entré dans une nouvelle appel récursif:
Puis, elle a invoqué le malloc de nouveau à l'intérieur de ce nouvel appel récursif. Cependant, cette fois, il a débordé:
[Le reste de la réponse est plus centrée autour de pourquoi j'ai eu ce problème dans mon code en particulier.]
Généralement, lors du calcul de Fibonacci de manière récursive, par exemple, d'un certain nombre n, la taille de la pile croît linéairement avec le nombre.
Toutefois, dans ce cas, je suis de la création des tâches, à l'aide d'une file d'attente pour les stocker, et la file d'attente d'un (fib) pour l'exécution de la tâche. Si vous faites cela sur le papier, vous aurez voir que le nombre de tâches augmente de façon exponentielle avec la n, plutôt que linéaire (à noter également que si j'avais utilisé une pile pour stocker les tâches qu'ils ont été créés, le nombre de tâches attribuées ainsi que la taille de la pile, ne fera que croître linéairement avec n. Donc ce qui se passe, c'est que la pile croît de façon exponentielle avec la n, conduisant à un dépassement de pile... Maintenant vient la partie pourquoi ce dépassement se produit à l'intérieur de l'appel à malloc. Donc, en gros, comme je l'ai expliqué ci-dessus, le débordement de la pile qui s'est passé à l'intérieur de la malloc appel, car c'était là que la pile a été la plus importante. Ce qui s'est passé est que la pile était sur le point d'exploser, et depuis malloc appels de fonctions à l'intérieur d'elle, la pile grandit de plus que juste l'appel de mywait et fib.
Merci à vous tous! Si ce n'était pas votre aide, je ne serais pas en mesure de le comprendre!
C'était ce que je me disais que je ne pouvais pas trouver n'importe quel problème. Mais pour s'assurer que c'est le problème pouvez-vous vider le 'top' de sortie sur un fichier et de vérifier comment l'utilisation de la mémoire? +1 pour la réponse et la question.
quand j'ai enlevé tous les threads, valgrind dit cela peut être un débordement de la pile, même si c'est peu probable. J'ai défini l'espace plus grand et que je ne puis exécuter plus fib nums. quand je double la taille de la pile, je ne peux qu'ajouter 1 au nombre précédent. Mais je vais faire comme vous l'avez dit, juste pour confirmer
OriginalL'auteur guilhermemtr