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 :

problème : adresse d'une variable globale modifiée


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre chevronné
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    1 855
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 1 855
    Par défaut problème : adresse d'une variable globale modifiée
    Bonjour,

    J'ai un problème sur un µControlleur 32bits (PIC32MX) avec le code suivant. L'adresse de la variable gblVar est modifiée lors d'appel de fonctions :
    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
    extern STRUCT_GLB gblVar; // défini dans un autre fichier .c
    int foo1(int a, int b, int c, int d);
    int foo2(int a, int b, int c, int d, MY_STRUCT * e);
     
    void init(void){
    	int a, b, c, d;
     
    	//...
     
    	printf("%p\n", &gblVar);
    	foo1(a, b, c, d);
    	printf("%p\n", &gblVar); // erreur : l'adresse a été modifiée (les deux octets de poids fort de l'adresse ont été mis à 0)
     
    	gblVar.x = 10; // le CPU génère une exception car l'adresse de la variable n'est plus valide
     
    	//...
    }
    Dans un autre fichier .c, j'ai :
    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
     
    int foo1(int a, int b, int c, int d);
    int foo2(int a, int b, int c, int d, MY_STRUCT * e);
     
    int foo1(int a, int b, int c, int d){
     
    	MY_STRUCT e;
     
    	e.a = 10;
    	// ...
    	e.z = 12;
     
    	return foo2(a, b, c, d, &e);
    }
     
    int foo2(int a, int b, int c, int d, MY_STRUCT * e){
     
    	// ...
     
    	return x;
    }

    Dans la fonction foo1(), si je remplace :
    Par :
    => je n'ai plus le problème.

    De quoi pourrait venir le problème ? Bug du compilateur/linkeur ?

    Merci d'avance

  2. #2
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 493
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 493
    Billets dans le blog
    1
    Par défaut
    Comment est définie la variable globale ? En quoi intervient-elle dans les fonctions foo1 et foo2 ?

  3. #3
    Membre chevronné
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    1 855
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 1 855
    Par défaut
    Dans un fichier .c, elle est déclarée comme ceci :
    un fichier .h lui est associé pour pouvoir l'utiliser dans d'autre fichiers .c :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    extern APP_STRUCT gblVar;
    La variable gblVar n'est pas utilisé dans les fonctions fooX(), elle est juste utilisé dans la fonction init() ... j'ai l'impression qu'il y a une altération de la pile mais je ne vois rien qui pourrait causer ça dans les fonctions foo1 et foo2.
    => je n'ai aucun warning/erreur lors de la compilation


    Si je modifie foo1() comme ceci :
    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
    int foo1(int a, int b, int c, int d){
     
    	MY_STRUCT e;
     
    	e.a = 10;
    	// ...
    	e.z = 12;
     
    	/* *** modif ***** */
    	int val;
    	val = foo2(a, b, c, d, &e);
     
    	printf("%p\n", &gblVar);
     
    	return val;
    }
    Le printf m'affiche l'adresse non erronée

  4. #4
    Membre Expert
    Avatar de skeud
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2011
    Messages
    1 091
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 1 091
    Billets dans le blog
    1
    Par défaut
    Tu as passé un coup de valgrind pour vérifier que tu n'as pas des erreurs cachées ailleur? En général, les soucis de pile se résolve facilement avec valgrind.

    J'ai un doute quand au return, ta variable e ne serait pas détruite avant l'appel de la fonction foo2?
    Genre si tu essaye de récupérer le retour de foo2 puis de le retourner, il se passe quoi?

  5. #5
    Membre chevronné
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    1 855
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 1 855
    Par défaut
    Hello, j'ai identifié l'erreur.

    Voici un exemple simplifié du problème.

    Je lance la fonction foo1 depuis ma fonction principale :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
     void foo1(){    
         MY_STRUCT aaa;    
         printf("sizeof(aaa) = %u\n", sizeof(aaa)); // ça affiche "sizeof(aaa) = 48"   // pourquoi la valeur ne vaut pas 64 ????????????????  
        // => Quand je lis le code assembleur (disassembly listing) de foo1(), la taille de aaa vaut 48 octets dans la stack software.
        //     Le backup des registres internes du CPU S0-S3 est placé dans la stack juste après aaa, ce qui fait que lors du memcpy du foo2(), ces valeurs sont écrasées => c'est ce qui génère le bug je pense, car le context est érroné lorsuqe je reviens dans ma fonction principale
     
         foo2(&aaa);    
     }    
     
     void foo2(MY_STRUCT * p){    
         memcpy(p, &glbVar2, sizeof(*p));    
     }
    => je n'ai aucune erreur de compilation


    J'ai controllé le code assembleur (disassembly listing) de foo2()
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    // Disassembly listing of foo2() function    
     734:                 void foo2(MY_STRUCT * p){    
     9D055188  27BDFFE8   ADDIU SP, SP, -24    
     9D055190  AFBF0014   SW RA, 20(SP)    
     735:                     memcpy(p, &glbVar, sizeof(*p));    
     9D055184  3C05A000   LUI A1, -24576    
     9D05518C  24A53E40   ADDIU A1, A1, 15936    
     9D055194  0F41A184   JAL 0x9D068610    
     9D055198  24060040   ADDIU A2, ZERO, 64 ///////////////////// value is good  ////////////////////    
     736:                 }    
     9D05519C  8FBF0014   LW RA, 20(SP)    
     9D0551A0  03E00008   JR RA    
     9D0551A4  27BD0018   ADDIU SP, SP, 24
    => il semble être bon

    Définition de ma structure :
    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
    #define TAB_ELMT_COUNT 2    
     typedef struct {  
         unsigned int x; // 4 bytes  
         unsigned int y; // 4 bytes  
     } INFO_STRUCT1;  
     typedef struct {  
         unsigned int a; // 4 bytes  
         unsigned int b; // 4 bytes  
     } INFO_STRUCT2;  
     
     typedef enum {  
         MY_ENUM_A = 0,  
         MY_ENUM_B = 0x8223,  
         MY_ENUM_C = 0x8823  
     } MY_ENUM; // 4 bytes  
     typedef struct {  
         MY_ENUM a; // 4 bytes  
         UINT16 b; // 2 bytes  
         UINT8 c; // 1 byte  
         // 1 bytes (padding)  
     
         BOOL d; // 4 bytes  
     } TAB_ELMT_STRUCT; // 12 bytes  
     
     typedef struct {  
         INFO_STRUCT1 info1; // 8 bytes  
         INFO_STRUCT2 info2; // 8 bytes  
     
         TAB_ELMT_STRUCT tab1[TAB_ELMT_COUNT]; // 12x2 = 24 bytes   
         TAB_ELMT_STRUCT tab2[TAB_ELMT_COUNT]; // 12x2 = 24 bytes   
     } MY_STRUCT; // 64 bytes
    => je n'arrive pas à voir pourquoi il y a un écart de 16 octets sur la taille de la structure suivant la fonction qui l'utilise.

    Une idée ?

    Je vois plusieurs causes possibles :
    - compilateur qui bug
    - déclaration de ma structure fausse (problème d'alignement) : pourtant elle me semble bonne (de plus je ne vois pas d'où pourrait venir la différence de 16 octets)...
    - options du compilateur fausses (pourtant, il me semble avoir les mêmes paramètres de configuration entre tous les fichiers .c)

  6. #6
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 397
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 397
    Par défaut
    Es-tu sûr des tailles de BOOL, int, MY_ENUM et TAB_ELEMENT_STRUCT sur ton microcontrôleur?

    À ta place, j'afficherais un sizeof de chaque, pour vérifier.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  7. #7
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 493
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 493
    Billets dans le blog
    1
    Par défaut
    As-tu vérifié les tailles de tous tes types avec des sizeof ? On a parfois des surprises.

    La norme dans mon souvenir ne garantit pas qu'un type énuméré soit codé sur 32 bits.

    Le padding, c'est parfois surprenant également.

    Moi, j'essaye de compter et j'arrive à ça par exemple :
    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
    #define TAB_ELMT_COUNT 2    
     typedef struct {  
         unsigned int x; // 4 bytes  
         unsigned int y; // 4 bytes  
     } INFO_STRUCT1;  
     
     typedef struct {  
         unsigned int a; // 4 bytes  
         unsigned int b; // 4 bytes  
     } INFO_STRUCT2;  
     
     typedef enum {  
         MY_ENUM_A = 0,  
         MY_ENUM_B = 0x8223,  
         MY_ENUM_C = 0x8823  
     } MY_ENUM; // 1 bytes  
     
     typedef struct {  
         MY_ENUM a; // 1 bytes  
         UINT16 b; // 2 bytes  
         UINT8 c; // 1 byte  
         BOOL d; // 4 bytes  
     } TAB_ELMT_STRUCT; // 8 bytes  
     
     typedef struct {  
         INFO_STRUCT1 info1; // 8 bytes  
         INFO_STRUCT2 info2; // 8 bytes  
     
         TAB_ELMT_STRUCT tab1[TAB_ELMT_COUNT]; // 8x2 = 16 bytes   
         TAB_ELMT_STRUCT tab2[TAB_ELMT_COUNT]; // 8x2 = 16 bytes   
     } MY_STRUCT; // 48 bytes
    CQFD ?

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

Discussions similaires

  1. problème avec une variable globale(SDL)
    Par rayman77 dans le forum C
    Réponses: 1
    Dernier message: 20/02/2009, 13h20
  2. modifier une variable globale
    Par bobo696 dans le forum Débuter
    Réponses: 2
    Dernier message: 22/01/2009, 11h42
  3. Problème pour modifier une variable globale
    Par supertom dans le forum EDI, CMS, Outils, Scripts et API
    Réponses: 6
    Dernier message: 07/06/2007, 18h00
  4. Problème d'adresse dans une variable
    Par mick77 dans le forum Macros et VBA Excel
    Réponses: 3
    Dernier message: 07/06/2007, 12h41
  5. Modifier une variable globale
    Par bahet dans le forum XSL/XSLT/XPATH
    Réponses: 2
    Dernier message: 19/04/2006, 18h04

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