IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

Comportement plus qu'étrange du malloc


Sujet :

C

  1. #1
    Membre averti
    Inscrit en
    Mai 2007
    Messages
    52
    Détails du profil
    Informations personnelles :
    Âge : 46

    Informations forums :
    Inscription : Mai 2007
    Messages : 52
    Par défaut Comportement plus qu'étrange du malloc
    Bonsoir à toutes et à tous,

    Je n'ai encore jamais rencontré un tel problème dans toute ma courte vie de programmation en C. Mais là, après des recherches qui n'en terminent plus, j'ai décidé de me tourner vers... les professionnels!

    Voici donc le problème qui me fait face depuis maintenant un certain temps. J'ai une fonction appelée depuis le programme central, dans laquelle un appel à malloc ne faillit (Segmentation fault) QUE dans certaines conditions. Voici le bout de code crucial:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    nwnz = numWtNonZero(argWt,prepareConf.conformerNum);
    printf("Found %ld non-zero weights\n",nwnz);
    nwnzW = (double *)malloc((nwnz+1)*sizeof(double));
    En fait, j'avais au début constaté que ce code ne fonctionnait que pour certaines valeurs de nznw (qui dépend des arguments passés).
    Bref, j'ai donc légèrement modifié le code pour voir quelles sont les valeurs qui passent, et celles qui ne passent pas. Voici le nouveau code:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    nwnz=numWtNonZero(argWt,prepareConf.conformerNum);
    printf("Found %ld non-zero weights\n",nwnz);
    nwnzW=(double *)malloc(18*sizeof(double));
    Manuellement, j'ai changé la valeur de (nwnz+1). Dans l'exemple ci-dessus, j'ai mis 18. Bien entendu, j'ai testé beaucoup de valeurs comme ça et il s'est avéré que pour TOUTE VALEUR COMPRISE ENTRE 5 ET 26 (inclus), ça plante. Par contre, si je mets une valeur de 1 à 4, ou supérieure à 26, tout marche pour le mieux.

    J'ai été encore plus loin. En fait, j'ai modifié une fois de plus le code de la façon suivante:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    nwnz=numWtNonZero(argWt,prepareConf.conformerNum);
    printf("Found %ld non-zero weights\n",nwnz);
    
    int j;
    for (j=0; j<100; j++)
    {
    	printf ("J = %d\n", j);
    	nwnzW = (double *)malloc(18*sizeof(double));
    }

    Dans ce code, j'ai aussi modifié manuellement la valeur du 18 que vous voyez, exactement de la même façon qu'avant. Les résultats sont pour moi pour le moins curieux...
    Si je mets une valeur de
    1 ==> Ca plante quand J = 4
    2 ==> Ca plante quand J = 3
    3 ==> Ca plante quand J = 2
    4 ==> Ca plante quand J = 2 (C'est bien 2 là...)
    5 ==> Ca plante quand J = 1 (Donc, dès la première tentative)
    6-26 ==> Ca plante quand J = 1
    >26 ==> Ca ne plante JAMAIS!

    Bref, quelqu'un aurait-il une quelconque idée de ce qui peut bien se tramer ici ?

    Par avance merci à toute réponse constructive,
    Mickaël

  2. #2
    Rédacteur

    Avatar de ram-0000
    Homme Profil pro
    Consultant en sécurité
    Inscrit en
    Mai 2007
    Messages
    11 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultant en sécurité
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2007
    Messages : 11 517
    Par défaut
    Je ne vois qu'une réponse à ton problème, c'est que la liste chainée interne de gestion de la mémoire dynamique est corrumpue et que cela se met en évidence avec certaines valeurs de malloc. Personnellement, je ne pense pas à un bug de malloc mais plutôt à un bug dans ton code avec quelqu'un qui va butiner la mémoire en dehors de son jardin.

    Une seule solution, tracer le code et les blocs alloués, regarder le code, regarder encore. vérifier que chaque malloc a son free (et un seul) et que chaque free a son malloc (et un seul) etc...
    Raymond
    Vous souhaitez participer à la rubrique Réseaux ? Contactez-moi

    Cafuro Cafuro est un outil SNMP dont le but est d'aider les administrateurs système et réseau à configurer leurs équipements SNMP réseau.
    e-verbe Un logiciel de conjugaison des verbes de la langue française.

    Ma page personnelle sur DVP
    .

  3. #3
    Membre Expert
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 104
    Par défaut
    J'ai une fonction appelée depuis le programme central, dans laquelle un appel à malloc ne faillit (Segmentation fault) QUE dans certaines conditions.
    A ma connaissance, un malloc ne plante pas, mais renvoie soit une adresse vers le bloc alloué en cas de réussite, soit NULL en cas d'échec, qu'il faut toujours tester.

    Comme ram-0000 le dit, à mon avis, un bout de code va accéder en dehors du bloc mémoire alloué (soit du débordes soit tu tapes carrément sur l'adresse correspondant à la valeur NULL) ou bien tu accèdes à un bloc mémoire déjà libéré.
    Mais comme tu ne donnes pas assez de code, on ne peut faire que des hypothèses.

    En outre, je vois d'affreux cast sur le retour de la fonction malloc, ce qui est parfaitement inutile en C, puisque le cast void*->type* et inversement se fait de manière implicite. Si c'est pour cacher un warning, c'est parce que tu as oublié d'inclure le fichier stdlib.h (obligatoire) et que le compilateur suppose que la fonction retourne un entier, ou si c'est pour cacher une erreur, c'est parce que tu compiles avec un compilateur C++ du code C (pas bien ! ces deux langages sont deux langages à part).

  4. #4
    Membre averti
    Inscrit en
    Mai 2007
    Messages
    52
    Détails du profil
    Informations personnelles :
    Âge : 46

    Informations forums :
    Inscription : Mai 2007
    Messages : 52
    Par défaut
    Merci pour vos réponses! J'apprécie beaucoup cette contribution qui en effet me révèle des détails très intéressants.

    Le code en C n'est pas de moi. Je dois simplement l'utiliser afin de faire des calculs. En fait, je me rends compte que vous avez entièrement raison, puisque la fonction malloc devrait en effet me retourner NULL en cas d'échec. Voici un peu plus de code, si ça vous intéresse (la bibliothèque stdlib:h est bien include):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    int switchAlg(double *argWt, energyStruct *myEnergy)
    {
    	/* The function switchAlg() attempts to minimize the constraint-based
    	/* [bla bla bla] 
    	* On Success, returns 0 
     	* On failure, returns -1
     	*/
    	char myBaseFileName[FILENAME_SIZE];
    
    	double	lowend=WEIGHT_IGNORANCE_BOUND;
    	double	worklowE;
    	double	lowestE;
    	double	step;
    	double	newnrg;
    	double	newwt;
    	double	thisactualstep;
    	double	actualstep;
    
    	double currentHot=0.0;
    
    	int gaveFullNoHangMessage=0;
    
    
    	int curRound,changenum,didAccept;
    	int nwnz,x,ox,i;
    	int noHang;
    	double ecfs=0;
    	double *nwnzW=(double *)NULL;
    	int *nwnzC=(int *)NULL;
    	FILE *f;
    	FILE *zf=(FILE *)NULL;
    
    	if (swConf.trackWts && malloc_sw_trackWts()!=0)
    	{
    		return -1;
    	}
    	if (swConf.trackAccept && malloc_sw_trackAccept()!=0)
    	{
    		return -1;
    	}
    
    	energyStruct tempEnergy = EMPTY_ENERGY_STRUCT;
    	energyStruct *energypA, *energypB, *energypX;
    
    	energypA = myEnergy;
    	energypB = &tempEnergy;
    
    	printf("Normalizing weights for switch routine\n");
    	if (normalize(argWt, prepareConf.conformerNum)!=0)
    	{
    		return -1;
    	}
    
    	nwnz = numWtNonZero(argWt,prepareConf.conformerNum);
    	printf("Found %ld non-zero weights\n",nwnz);
    
    	// Somehow crashing here
    	nwnzW=(double *)malloc((nwnz+1)*sizeof(double));
    	exit(0);	// Ceci m'a permis de tester si c'est bien l'appel à malloc qui fait tout planter
    	nwnzC=(int *)malloc((nwnz+1)*sizeof(int));
    
    	if (nwnzW==NULL || nwnzC==NULL)
    	{
    		printf("ERROR error Error (switchAlg): ");
    		printf("Unable to allocate memory for nwnzW of nwnzC\n");
    		return -1;
    	}
    	if (fillWtNonZero(nwnzW,nwnzC,argWt,prepareConf.conformerNum,nwnz)!=0)
    	{
    		printf("ERROR error Error (switchAlg): ");
    		printf("fillWtNonZero() returned non-zero.\n");
    		return -1;
    	}
    	
    	/* La suite de la fonction */
    	return 0;
    }
    Comme vous pouvez le voir, il y a bien un test de ce qui est retourné par la fontion malloc. Il semble donc que ce soit autre chose qui fasse planter le programme. Mais comme rien n'est exécuté entre le "Segmentation fault" et la fonction malloc (J'ai testé ça en mettant un exit(0); directement après la fonction), j'en ai juste déduit qu'il y avait un problème avec cette fonction. Voici la sortie (Je ne vous donne que les dernières lignes là...) que j'ai obtenu avec le code où j'intègre un compteur:

    """
    COMPUTATION, PLEASE WAIT:

    Normalizing weights for switch routine
    Found 5 non-zero weights
    J = 1
    Segmentation fault (core dumped)
    """

    Ce que je trouve d'extrêmement abhérant, c'est que ça plante pour une valeur (nwnz+1) de 26 et non pas de 27, ou encore que c'est la répétition avec une valeur (nwnz+1) inférieure à 5 qui fait tout planter!

    Sinon, jeroman, tu peux m'en dire un peu plus avec ta remarque: "En outre, je vois d'affreux cast sur le retour de la fonction malloc, ce qui est parfaitement inutile en C, puisque le cast void*->type* et inversement se fait de manière implicite". Je n'y voyais pas spécialement un problème. Qu'aurais-tu mis plus exactement ? En fait, on m'a toujours dit qu'en C, il valait toujours mieux déclarer les choses afin d'être sûr de comprendre ce qu'on fait...

    Merci en tout cas.

    A bientôt,
    Mickaël

  5. #5
    Rédacteur

    Avatar de ram-0000
    Homme Profil pro
    Consultant en sécurité
    Inscrit en
    Mai 2007
    Messages
    11 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultant en sécurité
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2007
    Messages : 11 517
    Par défaut
    Citation Envoyé par jeroman Voir le message
    A ma connaissance, un malloc ne plante pas
    Si si, cela peut planter car il y a une liste chainée des bloc de mémoires libres et alloués et si cette liste est altérée, la fonction malloc peut se planter en la parcourant.

    En fait, quant tu demandes/demandais 16 octets, malloc alloue/allouait un bloc de mémoire d'au moins 16 octets pour l'utilisateur et des octets supplémentaires juste avant le bloc utilisateur utilisé pour la gestion de cette liste chainée.

    Cette liste chainée permet de libérer très rapidement un bloc (le maillon de la liste chainée est marqué comme libre) et réallouer très rapidement la même taille (recherche d'un maillon de la taille demandée libre). Cela faisait office de cache puisque souvent les tailles de blocs demandées et libérées sont statistiquement identiques.

    C'était fait comme cela sur des implémentation de malloc/free/realloc que j'ai vu il y a quelques années.
    Raymond
    Vous souhaitez participer à la rubrique Réseaux ? Contactez-moi

    Cafuro Cafuro est un outil SNMP dont le but est d'aider les administrateurs système et réseau à configurer leurs équipements SNMP réseau.
    e-verbe Un logiciel de conjugaison des verbes de la langue française.

    Ma page personnelle sur DVP
    .

  6. #6
    Membre éprouvé
    Inscrit en
    Juin 2008
    Messages
    91
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 91
    Par défaut
    Je rajoute l'éventuel bogue malloc(0). La norme précise qu'il peut y avoir deux comportements possibles, le premier est un retour de NULL, donc le bogue est maîtrisé simplement par comparaison avec NULL; l'autre cas est l'envoi d'un pointeur non valide, donc le test != NULL ne voit que du vent, pourtant l'allocation a échoué et le pointeur retourné n'est pas valide.

    Je ne pense pas que ce soit le cas ici.

    Pour le cast explicite du retour de malloc, il est facultatif en C; mais rien n'empêche de le mettre. Cependant, il peut masquer certaines erreurs/manque de rigueur :

    - L'oublie de stdlib : si stdlib n'est pas incluse cela signifie que le compilateur déclarera la fonction malloc de façon implicite, ce qui veut dire que son type de retour sera celui par défaut à savoir le type int; or on l'affecte à un pointeur, donc il peut y avoir des problèmes à l'exécution.

    - Compilation avec un compilateur C++ : Là il n'y a pas autre chose à dire que C n'est pas C++, donc compiler avec un compilateur inadapté peut poser des problèmes difficilement détectables.

    Si ces choses sont maîtrisées alors mettre le cast ou ne pas le mettre est une question de gout.

  7. #7
    Membre averti
    Inscrit en
    Mai 2007
    Messages
    52
    Détails du profil
    Informations personnelles :
    Âge : 46

    Informations forums :
    Inscription : Mai 2007
    Messages : 52
    Par défaut
    Merci encore pour vos interventions qui ont su enrichir mes connaissances

    J'ai continué à chercher de mon côté pour essayer de comprendre, et j'ai remarqué que si j'allouais d'abord un espace mémoire assez grand que je ré-allouais pas la suite, ça passait niquel:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    	double *nwnzW=malloc(500*sizeof(double));	// Si je mets une valeur entre 5 et 26, ça plante
     
    	[La suite du code...]
     
    	nwnzW=realloc(nwnzW, 5*sizeof(double));		// Ca marche!!
    Si quelqu'un a une idée, je suis là aussi preneur!




    A côté de celà, sur un autre forum, quelqu'un a publié son problème qui se rapprochait un peu du mien. Un intervenant lui a conseillé de télécharger valgrind ( http://freshmeat.net/projects/valgrind/), qui me semblait être une potentielle solution à la compréhension de mon problème. J'ai relancé le programme suivant (que vous pouvez lire dans un précédent post, c'est juste pour vous rafraîchir la mémoire là...)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
    int switchAlg(double *argWt, energyStruct *myEnergy)
    {
    	/* The function switchAlg() attempts to minimize the constraint-based
    	/* [bla bla bla] 
    	* On Success, returns 0 
     	* On failure, returns -1
     	*/
     
    	[ Declaration de variables non essentielles au problème qui se pose]
    	double *nwnzW=NULL;	// Initialisation du pointeur
     
    	[Quelques lignes de codes où tout se passe bien (à priori)]
     
    	nwnzW = malloc(5*sizeof(double));			// C'est là que ça plante avec Seg. Fault.
     
    	if (nwnzW==NULL)
    	{
    		printf("ERROR error Error (switchAlg): ");
    		printf("Unable to allocate memory for nwnzW of nwnzC\n");
    		return -1;
    	}
    }

    La sortie du programme valgrind semble indiquer une fuite de mémoire, mais je ne comprends pas tout. Si quelqu'un pouvait m'expliquer ce qui se trame en lisant ces quelques lignes:

    COMPUTATION, PLEASE WAIT:

    Normalizing weights for switch routine
    Found 5 non-zero weights
    ==6009==
    ==6009== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 13 from 1)
    ==6009==
    ==6009== 1 errors in context 1 of 2:
    ==6009== Invalid read of size 4
    ==6009== at 0x807203E: malloc_shiftx_ensemble_variables (shiftx_lib.c:333)
    ==6009== by 0x804BF1A: readin_x (prepare_lib.c:1170)
    ==6009== by 0x804DDA4: prepare (prepare_lib.c:242)
    ==6009== by 0x80493F5: main (ensemble.c:320)
    ==6009== Address 0x4126C94 is 0 bytes after a block of size 132 alloc'd
    ==6009== at 0x4005525: malloc (vg_replace_malloc.c:149)
    ==6009== by 0x8071FB4: malloc_shiftx_ensemble_variables (shiftx_lib.c:319)
    ==6009== by 0x804BF1A: readin_x (prepare_lib.c:1170)
    ==6009== by 0x804DDA4: prepare (prepare_lib.c:242)
    ==6009== by 0x80493F5: main (ensemble.c:320)
    ==6009==
    ==6009== 1 errors in context 2 of 2:
    ==6009== Invalid write of size 4
    ==6009== at 0x8072037: malloc_shiftx_ensemble_variables (shiftx_lib.c:332)
    ==6009== by 0x804BF1A: readin_x (prepare_lib.c:1170)
    ==6009== by 0x804DDA4: prepare (prepare_lib.c:242)
    ==6009== by 0x80493F5: main (ensemble.c:320)
    ==6009== Address 0x4126C94 is 0 bytes after a block of size 132 alloc'd
    ==6009== at 0x4005525: malloc (vg_replace_malloc.c:149)
    ==6009== by 0x8071FB4: malloc_shiftx_ensemble_variables (shiftx_lib.c:319)
    ==6009== by 0x804BF1A: readin_x (prepare_lib.c:1170)
    ==6009== by 0x804DDA4: prepare (prepare_lib.c:242)
    ==6009== by 0x80493F5: main (ensemble.c:320)
    --6009--
    --6009-- supp: 13 dl-hack3
    ==6009==
    ==6009== IN SUMMARY: 2 errors from 2 contexts (suppressed: 13 from 1)
    ==6009==
    ==6009== malloc/free: in use at exit: 136,133 bytes in 40 blocks.
    ==6009== malloc/free: 326 allocs, 286 frees, 1,429,667 bytes allocated.
    ==6009==
    ==6009== searching for pointers to 40 not-freed blocks.
    ==6009== checked 161,424 bytes.
    ==6009==
    ==6009==
    ==6009== 40 bytes in 1 blocks are definitely lost in loss record 1 of 9
    ==6009== at 0x4005525: malloc (vg_replace_malloc.c:149)
    ==6009== by 0x8078FDC: switchAlg (switch_lib.c:394)
    ==6009== by 0x804E3C0: optimize (runtime_lib.c:835)
    ==6009== by 0x8049818: main (ensemble.c:567)
    ==6009==
    ==6009==
    ==6009== 132 bytes in 1 blocks are still reachable in loss record 2 of 9
    ==6009== at 0x4005525: malloc (vg_replace_malloc.c:149)
    ==6009== by 0x8071FB4: malloc_shiftx_ensemble_variables (shiftx_lib.c:319)
    ==6009== by 0x804BF1A: readin_x (prepare_lib.c:1170)
    ==6009== by 0x804DDA4: prepare (prepare_lib.c:242)
    ==6009== by 0x80493F5: main (ensemble.c:320)
    ==6009==
    ==6009==
    ==6009== 264 bytes in 1 blocks are still reachable in loss record 3 of 9
    ==6009== at 0x4005525: malloc (vg_replace_malloc.c:149)
    ==6009== by 0x804BC5C: malloc_ensemble_weights (prepare_lib.c:1231)
    ==6009== by 0x804DD84: prepare (prepare_lib.c:230)
    ==6009== by 0x80493F5: main (ensemble.c:320)
    ==6009==
    ==6009==
    ==6009== 513 bytes in 1 blocks are still reachable in loss record 4 of 9
    ==6009== at 0x4005525: malloc (vg_replace_malloc.c:149)
    ==6009== by 0x40055AF: realloc (vg_replace_malloc.c:306)
    ==6009== by 0x805169E: ensure_pdb_consistency (pdb_lib.c:75)
    ==6009== by 0x804DD5B: prepare (prepare_lib.c:217)
    ==6009== by 0x80493F5: main (ensemble.c:320)
    ==6009==
    ==6009==
    ==6009== 2,144 bytes in 1 blocks are definitely lost in loss record 5 of 9
    ==6009== at 0x4005525: malloc (vg_replace_malloc.c:149)
    ==6009== by 0x8072036: malloc_shiftx_ensemble_variables (shiftx_lib.c:332)
    ==6009== by 0x804BF1A: readin_x (prepare_lib.c:1170)
    ==6009== by 0x804DDA4: prepare (prepare_lib.c:242)
    ==6009== by 0x80493F5: main (ensemble.c:320)
    ==6009==
    ==6009==
    ==6009== 2,144 bytes in 1 blocks are still reachable in loss record 6 of 9
    ==6009== at 0x4005525: malloc (vg_replace_malloc.c:149)
    ==6009== by 0x8071FD7: malloc_shiftx_ensemble_variables (shiftx_lib.c:325)
    ==6009== by 0x804BF1A: readin_x (prepare_lib.c:1170)
    ==6009== by 0x804DDA4: prepare (prepare_lib.c:242)
    ==6009== by 0x80493F5: main (ensemble.c:320)
    ==6009==
    ==6009==
    ==6009== 9,648 bytes in 1 blocks are still reachable in loss record 7 of 9
    ==6009== at 0x4005622: realloc (vg_replace_malloc.c:306)
    ==6009== by 0x80721A3: get_shiftx_constraint (shiftx_lib.c:275)
    ==6009== by 0x804BF09: readin_x (prepare_lib.c:1167)
    ==6009== by 0x804DDA4: prepare (prepare_lib.c:242)
    ==6009== by 0x80493F5: main (ensemble.c:320)
    ==6009==
    ==6009==
    ==6009== 52,640 bytes in 1 blocks are still reachable in loss record 8 of 9
    ==6009== at 0x4005525: malloc (vg_replace_malloc.c:149)
    ==6009== by 0x8050EC7: malloc_atom_for_pdbgopher (pdb_lib.c:332)
    ==6009== by 0x804DD74: prepare (prepare_lib.c:224)
    ==6009== by 0x80493F5: main (ensemble.c:320)
    ==6009==
    ==6009==
    ==6009== 68,608 bytes in 32 blocks are still reachable in loss record 9 of 9
    ==6009== at 0x4005525: malloc (vg_replace_malloc.c:149)
    ==6009== by 0x8072036: malloc_shiftx_ensemble_variables (shiftx_lib.c:332)
    ==6009== by 0x804BF1A: readin_x (prepare_lib.c:1170)
    ==6009== by 0x804DDA4: prepare (prepare_lib.c:242)
    ==6009== by 0x80493F5: main (ensemble.c:320)
    ==6009==
    ==6009== LEAK SUMMARY:
    ==6009== definitely lost: 2,184 bytes in 2 blocks.
    ==6009== possibly lost: 0 bytes in 0 blocks.
    ==6009== still reachable: 133,949 bytes in 38 blocks.
    ==6009== suppressed: 0 bytes in 0 blocks.
    --6009-- memcheck: sanity checks: 16 cheap, 1 expensive
    --6009-- memcheck: auxmaps: 0 auxmap entries (0k, 0M) in use
    --6009-- memcheck: auxmaps: 0 searches, 0 comparisons
    --6009-- memcheck: SMs: n_issued = 33 (528k, 0M)
    --6009-- memcheck: SMs: n_deissued = 0 (0k, 0M)
    --6009-- memcheck: SMs: max_noaccess = 65535 (1048560k, 1023M)
    --6009-- memcheck: SMs: max_undefined = 0 (0k, 0M)
    --6009-- memcheck: SMs: max_defined = 29 (464k, 0M)
    --6009-- memcheck: SMs: max_non_DSM = 33 (528k, 0M)
    --6009-- memcheck: max sec V bit nodes: 0 (0k, 0M)
    --6009-- memcheck: set_sec_vbits8 calls: 0 (new: 0, updates: 0)
    --6009-- memcheck: max shadow mem size: 832k, 0M
    --6009-- translate: fast SP updates identified: 3,904 ( 88.7%)
    --6009-- translate: generic_known SP updates identified: 317 ( 7.2%)
    --6009-- translate: generic_unknown SP updates identified: 177 ( 4.0%)
    --6009-- tt/tc: 13,924 tt lookups requiring 15,457 probes
    --6009-- tt/tc: 13,924 fast-cache updates, 3 flushes
    --6009-- transtab: new 4,135 (91,248 -> 1,420,377; ratio 155:10) [0 scs]
    --6009-- transtab: dumped 0 (0 -> ??)
    --6009-- transtab: discarded 6 (146 -> ??)
    --6009-- scheduler: 1,642,862 jumps (bb entries).
    --6009-- scheduler: 16/10,461 major/minor sched events.
    --6009-- sanity: 17 cheap, 1 expensive checks.
    --6009-- exectx: 30,011 lists, 50 contexts (avg 0 per list)
    --6009-- exectx: 627 searches, 577 full compares (920 per 1000)
    --6009-- exectx: 113 cmp2, 39 cmp4, 0 cmpAll
    Merci d'avance à toute remarque pertinente et/ou instructive,
    Mickaël

  8. #8
    Rédacteur

    Avatar de ram-0000
    Homme Profil pro
    Consultant en sécurité
    Inscrit en
    Mai 2007
    Messages
    11 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultant en sécurité
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2007
    Messages : 11 517
    Par défaut
    Citation Envoyé par mkrzemin Voir le message
    J'ai continué à chercher de mon côté pour essayer de comprendre, et j'ai remarqué que si j'allouais d'abord un espace mémoire assez grand que je ré-allouais pas la suite, ça passait niquel:
    C'est typique d'un comportement indéterminé, quelqu'un jardine dans un jardin qui n'est pas le sien et tout et son contraire peut se produire. Il n'y a pas de logique compréhensible.

    Citation Envoyé par mkrzemin Voir le message
    A côté de celà, sur un autre forum, quelqu'un a publié son problème qui se rapprochait un peu du mien. Un intervenant lui a conseillé de télécharger valgrind ( http://freshmeat.net/projects/valgrind/), qui me semblait être une potentielle solution à la compréhension de mon problème.
    Valgrind est une solution pour t'aider à rechercher ton problème (il y a aussi des solution payantes comme purify).

    Citation Envoyé par mkrzemin Voir le message
    La sortie du programme valgrind semble indiquer une fuite de mémoire, mais je ne comprends pas tout. Si quelqu'un pouvait m'expliquer ce qui se trame en lisant ces quelques lignes:
    Une fuite de mémoire (et il semble effectivemlent que tu en aies) n'est pas le problème pour l'instant, ce n'est pas bien mais tu peux vivre avec, cela ne provoque pas de crash ni de bug, c'est juste "pas propre".

    Citation Envoyé par mkrzemin Voir le message
    Merci d'avance à toute remarque pertinente et/ou instructive,
    Dommage, je ne sais pas t'aider pour lire les sorties Valgrind.

    Par contre et en priorité, je me concentrerais sur ces 2 erreurs :
    • ==6009== 1 errors in context 1 of 2: ==6009== Invalid read of size 4
    • ==6009== 1 errors in context 2 of 2: ==6009== Invalid write of size 4


    La fin du rapport, c'est les memory leaks (blocs alloués mais non libérés). C'est à traiter mais en final.

    D'autres pistes, mettre Valgrind en mode "plus verbeux encore", je ne sais pas si c'est possible

    Faire un ou des programmes de test qui fait des allocation mémoire et du grand n'importe quoi sur ces allocations pour voir comment Vlagrind se comporte :
    • allouer 32 actets et écrire 100 octets dedans
    • lire 100 octets dans un buffer alloué de 32 octets
    • faire un double free
    • ...
    Raymond
    Vous souhaitez participer à la rubrique Réseaux ? Contactez-moi

    Cafuro Cafuro est un outil SNMP dont le but est d'aider les administrateurs système et réseau à configurer leurs équipements SNMP réseau.
    e-verbe Un logiciel de conjugaison des verbes de la langue française.

    Ma page personnelle sur DVP
    .

  9. #9
    Membre averti
    Inscrit en
    Mai 2007
    Messages
    52
    Détails du profil
    Informations personnelles :
    Âge : 46

    Informations forums :
    Inscription : Mai 2007
    Messages : 52
    Par défaut
    SOLUTION TROUVEE!

    Merci en tout cas ram-0000 pour ta dernière intervention. En fait, j'ai pris un peu plus de temps à comprendre la sortie de Valgrind. J'ai consulté quelques sites qui expliquaient comment interpréter la sortie.

    Valgrind indiquait bien une fuite de mémoire, et plus précisemment, une perte d'octets:
    ==6009== LEAK SUMMARY:
    ==6009== definitely lost: 2,184 bytes in 2 blocks.
    Une part de cette perte était due au fait que je stoppais le programme précocemment afin de vérifier que l'erreur arrivait bien au moment de l'appel à malloc (J'avais mis un exit(0); juste après). En effet, j'allouais de la mémoire avec malloc, mais je ne me servais pas du contenu de la variable accessible via le pointeur ainsi déclaré.
    La deuxième fuite arrivait beaucoup plus tôt dans le code. Voici les lignes qui étaient à l'origine de l'erreur qui ne se produisait que beaucoup plus tard:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
    	//First initialize shiftxCalc
    	shiftxCalc=(double **)malloc((prepareConf.conformerNum+1)*sizeof(double *));
    	if(shiftxCalc==NULL) {
    		printf("ERROR error Error (malloc_shiftx_ensemble_variables): ");
    		printf("Unable to allocate memory for shiftxCalc.\n");
    		return -1;
    	}
    	shiftxCalc[0]=(double *)malloc((shiftxConf.constraintNum+1)*sizeof(double));
    	if(shiftxCalc[0]==NULL) {
    		printf("ERROR error Error (malloc_shiftx_ensemble_variables): ");
    		printf("Unable to allocate memory for shiftxCalc.\n");
    		return -1;
    	}
    	for (i=1;i<=prepareConf.conformerNum+1;i++){
    		shiftxCalc[i]=(double *)malloc((shiftxConf.constraintNum+1)*sizeof(double));
    		if(shiftxCalc[i]==NULL) {
    			printf("ERROR error Error (malloc_shiftx_ensemble_variables): ");
    			printf("Unable to allocate memory for shiftxCalc.\n");
    			return -1;
    		}
    		shiftxCalc[i][0] = 0.0;
    	}
    En regardant ce code d'un peu plus près, on s'aperçoit que dans la dernière boucle, la variable i parcourt des valeurs allant de 1 à (prepareConf.conformerNum+1) INCLUS. Or un peu plus haut, dans la déclaration même de shiftxCalc, l'allocation de mémoire n'est faite que pour (prepareConf.conformerNum+1) blocs. En d'autre termes, la dernière boucle essaie d'initialiser un bloc qui sort des limites du double pointeur. Ce qui est étrange, c'est que le programme n'a jamais occasionné un Segmentation fault à ce niveau...

    Par contre, quelqu'un saurait m'expliquer pourquoi le programmeur a d'abord allouer de l'espace uniquement pour le bloc 0 avant de l'allouer pour le reste des blocs ? Dans mon cas, j'ai simplement transformé ce bout de code en:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
    	// Initialization of shiftxCalc
    	if ((shiftxCalc = malloc((prepareConf.conformerNum+1)*sizeof(double *))) == NULL)
    	{
    		printf("ERROR error Error (malloc_shiftx_ensemble_variables): ");
    		printf("Unable to allocate memory for shiftxCalc.\n");
    		return -1;
    	}
     
    	for (i=0; i<=prepareConf.conformerNum; i++)
    	{
    		if ((shiftxCalc[i] = malloc((shiftxConf.constraintNum+1)*sizeof(double))) == NULL)
    		{
    			printf("ERROR error Error (malloc_shiftx_ensemble_variables): ");
    			printf("Unable to allocate memory for shiftxCalc.\n");
    			return -1;
    		}
    		shiftxCalc[i][0] = 0.0;
    	}
    Encore merci à tous les intervenants,
    Mickaël

  10. #10
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 815
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 815
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par mkrzemin Voir le message
    SOLUTION TROUVEE!
    La deuxième fuite arrivait beaucoup plus tôt dans le code. Voici les lignes qui étaient à l'origine de l'erreur qui ne se produisait que beaucoup plus tard:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
    	//First initialize shiftxCalc
    	shiftxCalc=(double **)malloc((prepareConf.conformerNum+1)*sizeof(double *));
    	if(shiftxCalc==NULL) {
    		printf("ERROR error Error (malloc_shiftx_ensemble_variables): ");
    		printf("Unable to allocate memory for shiftxCalc.\n");
    		return -1;
    	}
    	shiftxCalc[0]=(double *)malloc((shiftxConf.constraintNum+1)*sizeof(double));
    	if(shiftxCalc[0]==NULL) {
    		printf("ERROR error Error (malloc_shiftx_ensemble_variables): ");
    		printf("Unable to allocate memory for shiftxCalc.\n");
    		return -1;
    	}
    	for (i=1;i<=prepareConf.conformerNum+1;i++){
    		shiftxCalc[i]=(double *)malloc((shiftxConf.constraintNum+1)*sizeof(double));
    		if(shiftxCalc[i]==NULL) {
    			printf("ERROR error Error (malloc_shiftx_ensemble_variables): ");
    			printf("Unable to allocate memory for shiftxCalc.\n");
    			return -1;
    		}
    		shiftxCalc[i][0] = 0.0;
    	}
    En regardant ce code d'un peu plus près, on s'aperçoit que dans la dernière boucle, la variable i parcourt des valeurs allant de 1 à (prepareConf.conformerNum+1) INCLUS. Or un peu plus haut, dans la déclaration même de shiftxCalc, l'allocation de mémoire n'est faite que pour (prepareConf.conformerNum+1) blocs. En d'autre termes, la dernière boucle essaie d'initialiser un bloc qui sort des limites du double pointeur.
    Super bien vu !!! Très bel exemple de programmation moisie. Le truc qu'on est content de ne pas avoir à débugguer quoi...

    Citation Envoyé par mkrzemin Voir le message
    Ce qui est étrange, c'est que le programme n'a jamais occasionné un Segmentation fault à ce niveau...
    C'est typique du "comportement indéterminé" => comportement dont tu ne peux pas garantir le résultat => tu ne peux donc pas présumer qu'il y aura un segfault si tu dépasses les limites. Si tu as du bol tu as un segfault juste après avoir écrit ce code et donc tu peux te dire "ok, j'ai tapé ces 15 lignes et j'ai un segfault => l'erreur est dans ces 15 lignes". Si t'as pas de bol, tout se passe semble-t-il parfaitement et 6 mois plus tard tu rajoutes un malloc à la con 40 lignes plus bas et là, le segfault apparait. Et là, ben tu cherches bien évidemment dans les lignes que tu viens juste d'ajouter et tu cherches, tu cherches, tu cherches...

    Citation Envoyé par mkrzemin Voir le message
    Par contre, quelqu'un saurait m'expliquer pourquoi le programmeur a d'abord allouer de l'espace uniquement pour le bloc 0 avant de l'allouer pour le reste des blocs ?
    Non. On aurait pu croire que la première allocation est différente mais non, là j'ai pas d'idée. Mais j'ai déjà vu des codes de ce type où on fait un truc apparemment inutile au départ mais en fait c'est super bien pensé parce que ça permet à la bobinette de choir d'une certaine façon si on tire la chevillette d'une autre façon. Bref des trucs de super pros malheureusement super pas commentés et dont l'ésotérique super secret disparait à leur mort. Donc à mon avis, supprimer l'allocation [0] et l'intégrer dans la boucle ne nuira pas à ton code...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  11. #11
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    340
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 340
    Par défaut
    quand valgrind me reporte

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    ==6009== Invalid read of size 4
    je regarde bien comme il faut pourquoi il y a un invalid read (pareil pour les write). Typiquement, tu lis (resp. ecrit) dans un endroit de la memoire alors que tu ne devrais pas. D'ou problemes de seg fault ou de stack (les pires)

  12. #12
    Membre averti
    Inscrit en
    Mai 2007
    Messages
    52
    Détails du profil
    Informations personnelles :
    Âge : 46

    Informations forums :
    Inscription : Mai 2007
    Messages : 52
    Par défaut
    Merci Sve@r pour tes commentaires. Etant donné que je ne suis pas particulièrement un pro du C (Je suis plus Python en fait), en effet, je ne vais pas m'ennuyer à essayer de comprendre pourquoi agir sur le bloc 0 avant de faire exactement la même chose sur les blocs restants...

    Quant à ta question d'Oursse, je la trouve plutôt intéressante. Dites moi si je me trompe, mais je pense que ça vient de la lecture d'un pointeur (qui a une taille de 4 octets) qui n'appartient à aucune "table". En d'autres termes, tu définit d'abord un pointeur qui pointe sur un ensemble de pointeurs. Et tu essaies ensuite de lire plus loin que le nombre de pointeurs définit.

    Mickaël

  13. #13
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 815
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 815
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par mkrzemin Voir le message
    Quant à ta question d'Oursse, je la trouve plutôt intéressante. Dites moi si je me trompe, mais je pense que ça vient de la lecture d'un pointeur (qui a une taille de 4 octets) qui n'appartient à aucune "table". En d'autres termes, tu définit d'abord un pointeur qui pointe sur un ensemble de pointeurs. Et tu essaies ensuite de lire plus loin que le nombre de pointeurs définit.
    Aucune idée si c'est ça qui cause le warning. Mais bon, faut bien comprendre que la mémoire c'est une gigantesque zone. Si on te réserve 10 octets dans cette zone entre les adresses 0xa0 et 0xaa, c'est pas pour ça que l'adresse suivante 0xab est en dehors de tout. 0xab c'est simplement l'adresse qui suit 0xaa. La seule différence entre 0xaa et 0xab, c'est que la première se situe dans la zone qui t'es réservée mais pas la seconde. Si valgrind est capable de détecter ça, alors c'est bien vu.
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Comportement de timer étrange
    Par Kikouyou1080 dans le forum VB.NET
    Réponses: 2
    Dernier message: 29/04/2010, 19h57
  2. [AC-2003] Comportement de requête étrange ?
    Par tibofo dans le forum Requêtes et SQL.
    Réponses: 1
    Dernier message: 04/08/2009, 16h35
  3. Comportement Form Maximize étrange
    Par portu dans le forum Composants VCL
    Réponses: 3
    Dernier message: 03/10/2008, 17h11
  4. Réponses: 23
    Dernier message: 23/01/2006, 21h31

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo