95 votes

Pourquoi est-ce que j'obtiens un échec d'assertion C malloc ?

Je suis en train d'implémenter un algorithme polynomial de type diviser et conquérir afin de pouvoir le comparer à une implémentation OpenCL, mais je n'arrive pas à obtenir malloc pour travailler. Lorsque j'exécute le programme, il alloue un tas de choses, vérifie certaines choses, puis envoie l'adresse de l'ordinateur. size/2 à l'algorithme. Ensuite, quand j'ai atteint le malloc Encore une fois, il sort ceci :

malloc.c:3096: sYSMALLOc: Assertion `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 * (sizeof(size_t))) - 1)) & ~((2 * (sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long)old_end & pagemask) == 0)' failed.
Aborted

La ligne en question est :

int *mult(int size, int *a, int *b) {
    int *out,i, j, *tmp1, *tmp2, *tmp3, *tmpa1, *tmpa2, *tmpb1, *tmpb2,d, *res1, *res2;
    fprintf(stdout, "size: %d\n", size);

    out = (int *)malloc(sizeof(int) * size * 2);
}

J'ai vérifié la taille avec un fprintf et c'est un nombre entier positif (généralement 50 à ce stade). J'ai essayé d'appeler malloc avec un numéro simple également et j'ai toujours l'erreur. Je ne comprends pas ce qui se passe, et rien de ce que j'ai trouvé sur Google n'est utile.

Une idée de ce qui se passe ? J'essaie de trouver comment compiler un GCC plus récent au cas où il s'agirait d'une erreur de compilation, mais j'en doute vraiment.

0 votes

Je pense que le problème se situe en fait une ligne avant celle-ci. Peut-être un double libre ?

0 votes

3ème ligne du programme : int *mult(int size, int *a, int *b) { int *out,i, j, *tmp1, *tmp2, *tmp3, *tmpa1, *tmpa2, *tmpb1, *tmpb2,d, *res1, *res2 ; fprintf(stdout, "size : %d \n ", size) ; out = (int *)malloc(sizeof(int) * size * 2) ;

110voto

R Samuel Klatchko Points 44549

Il est probable à 99,9 % que vous ayez corrompu la mémoire (débordement ou sous-débordement d'un tampon, écriture sur un pointeur après sa libération, double appel à free sur le même pointeur, etc.)

Exécutez votre code sous Valgrind pour voir où votre programme a fait quelque chose d'incorrect.

3 votes

Réparé. Valgrind m'a définitivement aidé. J'ai mal transcrit mon ancien code Matlab et j'avais une boucle for qui itérait sur j, puis à l'intérieur elle faisait j++ ce qui écrasait le tableau sur lequel elle écrivait et d'une certaine manière faisait échouer malloc. merci pour l'aide !

1 votes

Valgrind était justement l'outil dont j'avais besoin pour comprendre ce qui se passait lorsque j'ai eu cette erreur. Merci de l'avoir mentionné.

0 votes

Vérifiez ma réponse ci-dessous pour une solution utilisant le désinfectant d'adresse pour une utilisation plus facile et un meilleur guide / illustration.

83voto

Jonhoo Points 849

Pour vous permettre de mieux comprendre pourquoi Si cela se produit, j'aimerais développer un peu la réponse de @r-samuel-klatchko.

Lorsque vous appelez malloc mais ce qui se passe réellement est un peu plus compliqué que de vous donner un morceau de mémoire avec lequel jouer. Sous le capot, malloc conserve également des informations sur la mémoire qu'il vous a donnée (le plus important étant sa taille), de sorte que lorsque vous appelez free il sait, par exemple, combien de mémoire il doit libérer. Cette information est généralement conservée juste avant l'emplacement de la mémoire qui vous est retourné par la fonction malloc . Des informations plus exhaustives peuvent être trouvées sur l'internet™ mais l'idée (très) simple est la suivante :

+------+-------------------------------------------------+
+ size |                  malloc'd memory                +
+------+-------------------------------------------------+
       ^-- location in pointer returned by malloc

À partir de là (et en simplifiant grandement les choses), lorsque vous appelez malloc il doit obtenir un pointeur vers la prochaine partie de la mémoire disponible. Une façon très simple de le faire est de regarder la partie précédente de la mémoire qu'il a donnée, et de déplacer le pointeur vers la partie suivante de la mémoire disponible. size octets plus bas (ou plus haut) dans la mémoire. Avec cette implémentation, votre mémoire ressemble à quelque chose comme ceci après l'allocation de p1 , p2 y p3 :

+------+----------------+------+--------------------+------+----------+
+ size |                | size |                    | size |          +
+------+----------------+------+--------------------+------+----------+
       ^- p1                   ^- p2                       ^- p3

Alors, quelle est la cause de votre erreur ?

Imaginons que votre code écrive par erreur au-delà de la quantité de mémoire que vous avez allouée (soit parce que vous avez alloué moins que nécessaire, comme c'était votre problème, soit parce que vous utilisez les mauvaises conditions limites quelque part dans votre code). Disons que votre code écrit tant de données dans p2 qu'il commence à écraser ce qui est dans p3 's size champ. Lors de votre prochain appel malloc il examinera le dernier emplacement mémoire qu'il a renvoyé, regardera son champ de taille, se déplacera vers p3 + size et ensuite commencer à allouer de la mémoire à partir de là. Puisque votre code a écrasé size Cependant, cet emplacement de mémoire ne se trouve plus après la mémoire précédemment allouée.

Inutile de dire que cela peut faire des ravages ! Les responsables de la mise en œuvre de malloc ont donc intégré un certain nombre d'"assertions", ou de vérifications, qui tentent d'effectuer un certain nombre de vérifications de l'intégrité afin de détecter ce problème (et d'autres) s'ils sont sur le point de se produire. Dans votre cas particulier, ces assertions sont violées, et donc malloc s'interrompt, vous indiquant que votre code était sur le point de faire quelque chose qu'il ne devrait vraiment pas faire.

Comme indiqué précédemment, il s'agit d'une simplification excessive, mais elle suffit à illustrer le propos. L'implémentation glibc de malloc est plus de 5k lignes, et il y a eu des quantités substantielles de recherche sur la façon de construire de bons mécanismes d'allocation de mémoire dynamique, donc couvrir tout cela dans une réponse SO n'est pas possible. J'espère que cela vous a donné une idée de ce qui cause réellement le problème !

0 votes

C'est vraiment utile !

2voto

pbernatchez Points 231

Vous dépassez probablement la mémoire allouée quelque part. alors le programme sous-jacent ne s'en rend pas compte jusqu'à ce que vous appeliez malloc.

Il se peut qu'il y ait une valeur de garde bloquée qui est prise par malloc.

edit...ajouté ceci pour l'aide à la vérification des bornes

http://www.lrde.epita.fr/~akim/ccmp/doc/bounds-checking.html

0voto

Phob Points 588

Nous avons obtenu cette erreur parce que nous avons oublié de multiplier par sizeof(int). Notez que l'argument de malloc(..) est un nombre d'octets, pas un nombre de mots machine ou autre.

-1voto

JMH Points 1

J'ai porté une application de Visual C vers gcc sous Linux et j'ai eu le même problème avec

malloc.c:3096 : sYSMALLOc : Assertion utilisant gcc sur UBUNTU 11.

J'ai déplacé le même code vers une distribution Suse (sur un autre ordinateur) et je n'ai aucun problème.

Je soupçonne que les problèmes ne sont pas dans nos programmes mais dans la libc.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X