Pas de plantage avec Valgrind mais plantage sans

a marqué ce sujet comme résolu.

Bonjour,

Quand j’effectue une certaine procédure dans mon programme, lancé en terminal de commande, celui-ci plante (segfault). Je suspecte un pointeur d’être à l’origine du problème et je ne pense pas me tromper car lors de l’affichage de son adresse il a toujours une adresse mémoire très faible (48, 100, etc..) comparé à son adresse dans un "cas normal" qui est entièrement aléatoire je sais mais qui d’habitude n’a pas du tout une valeur aussi faible.

Cependant, quand j’utilise valgrind (avec l’option –leak-check=full), en suivant les mêmes étapes d’utilisation, mon programme fonctionne parfaitement normalement.

Comment faire pour trouver l’origine de mon problème ?

Merci d’avance.

+0 -0

Hummm … intéressant.

Tu compiles bien en debug ? Valgrind ne te sort aucune information ?

+0 -0

Hummm … intéressant.

Tu compiles bien en debug ? Valgrind ne te sort aucune information ?

ache

C’est pas etonnant. Valgrind va détecter des accès mémoires non valides. S’il sort d’un tableau mais qu’il écrase de la mémoire valide qui lui appartient, il peut tout à fait pourrir un pointeur et que valgrind ne voit rien.

+0 -0

Biensûr, je pense à la même chose mais ça va à l’encontre de ce que l’OP décrit dans son premier message.

0x30 ça ressemble à un pointeur invalide, je suis assez d’accord avec lui (et je pense que toi aussi).

+0 -0

Merci pour vos réponses ! Je vais essayer cet après-midi led outils que tu proposes.

Je compile bien en debug, et j’ai déjà utilisé valgrind pour d’autres problèmes avec succès.

J’initialise un tableau de pointeurs de structure dynamiquement, puis je commence a initialiser les pointeurs avec des malloc et j’arrête dès qu’il y a un problème.

Mon problème c’est que lors de la destruction des pointeurs, même avec les tests d’existence du pointeur, il accède à des adresses qui sont très faibles. Est ce que ça peut être parce que tout les pointeurs du tableau de pointeurs de structure n’ont pas eu une valeur par défaut et que je dois dans tout les cas mettre tout les pointeurs à null au début avant d’essayer de les initialiser ?

+0 -0

malloc n’initialise rien du tout. C’est écrit dans la man de malloc, deuxième phrase :

The memory is not initialized

Rajoute une boucle pour les affecter à NULL, ou utilise calloc pour les "initialiser" à 0. Mais si après tu es certains que tu les affectes tous à une valeur valide alors peu importe qu’ils aient une valeur aléatoire. Sinon, même avec tes explications j’ai du mal à comprendre. Montre un bout de code quand tu pourras.

De ce que je comprend :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
size_t nbElem = ?;
typeStruct** tab = malloc( sizeof(typeStruct*) * nbElem);

if( !tab ) exit(0);

for(size_t i = 0 ; i < nbElem ; i++) {
   typeStruct* tmp = malloc( sizeof(typeStruct) ); // J'imagine qu'il y a un * nbElem encore sinon, je ne comprend l'intéret
   if( !tmp ) break;
   tab[i] = tmp;
}
// [...]
for(size_t i = 0 ; i < nbElem ; i++) {
   free(tab[i]);
}

Ce qui pose effectivement un problème à cause de la non initialisation de malloc.

+0 -0

NB: les segfault ce n’est pas un problème de leak, c’est plus souvent un problème d’écriture à une adresse qui ne nous appartient pas.

En général, valgrind sans option particulière suffit. Il suffit de tordre les erreurs et warnings les uns après les autres (en commençant par le premier signalé).

Sinon +1 à l’adress sanitizer. J’aime bien l’undefined sanitizer aussi. Accessoirement, un clang récent avec -wall va être capable de signaler certains cas d’utilisation de données non initialisées, ce qui est juste énorme.

@ache Effectivement c’était bien ça, il fallait que j’utilise calloc. Ton code représente très bien la situation (modulo le nom des structures et variables), c’est juste que j’ai oublié que malloc ne met pas à NULL obligatoirement, et j’arrête la lecture du fichier en cas de problème sur les données donc je ne terminais pas forcément ma boucle au nombre maximum, ce qui faisait que certains pointeurs de pointeurs ne pointaient pas sur quelque chose de défini.

Du coup vous avez l’air très compétent sur ce sujet, donc j’ai deux questions:

-Comment le programme sait qu’il n’a pas le droit de modifier cette adresse ?

-Valgrind me sort un warning sur le strcopy quand je fais ce bout de code:

1
2
3
//enleve les espaces au debut des lignes lues du fichier en cours de lecture
sscanf(tab, " %n", &char_used);
strcpy(tab, &tab[char_used]);

Est-ce que memcpy serait plus judicieux dans mon cas ?

Merci encore :)

+0 -0

Comment le programme sait qu’il n’a pas le droit de modifier cette adresse ?

En fait, le programme n’en a pas la moindre idée. Il demande l’accès au système d’exploitation, et là, le système lui dit juste de dégager, qu’il n’a rien à faire ici.

Pour faire ça, le système alloue des zones mémoires, il sait a qui appartient telle zone, et si tu n’as pas le droit d’y accéder, alors tu connais la suite !

-Valgrind me sort un warning sur le strcopy quand je fais ce bout de code:

1
2
3
//enleve les espaces au debut des lignes lues du fichier en cours de lecture
sscanf(tab, " %n", &char_used);
strcpy(tab, &tab[char_used]);

Est-ce que memcpy serait plus judicieux dans mon cas ?

Merci encore :)

Unknown

Effectivement, le problème est que les chaînes tab et &tab[char_used] se chevauchent, et tu ne peux pas utiliser strcpy dans ce cas :

The strcpy function copies the string pointed to by s2 (including the terminating null character) into the array pointed to by s1. If copying takes place between objects that overlap, the behavior is undefined.

memcpy souffre du même problème, par contre tu peux utiliser memmove (c’est fait pour ça !). L’occasion de rappeler l’existence de ce tuto sur des sujets connexes.

Je plussoie la réponse de Lucas-84 et encore merci pour ce tutoriel 💞

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte