CONNEXION
  • RetourJeux
    • Sorties
    • Hit Parade
    • Les + populaires
    • Les + attendus
    • Soluces
    • Tous les Jeux
    • Gaming
  • RetourActu Gaming
    • News
    • Astuces
    • Tests
    • Previews
    • Toute l'actu gaming
  • RetourBons plans
    • Bons plans
    • Bons plans Smartphone
    • Bons plans Hardware
    • Bons plans Image et Son
    • Bons plans Amazon
    • Bons plans Cdiscount
    • Bons plans Decathlon
    • Bons plans Fnac
    • Tous les Bons plans
  • RetourJVTech
    • Actus High-Tech
    • Intelligence Artificielle
    • Smartphones
    • Mobilité urbaine
    • Hardware
    • Image et son
    • Tutoriels
    • Tests produits High-Tech
    • Guides d'achat High-Tech
    • JVTech
  • RetourCulture
    • Actus Culture
    • Culture
  • RetourVidéos
    • A la une
    • Gaming Live
    • Vidéos Tests
    • Vidéos Previews
    • Gameplay
    • Trailers
    • Chroniques
    • Replay Web TV
    • Toutes les vidéos
  • RetourForums
    • Hardware PC
    • PS5
    • Switch 2
    • Xbox Series
    • Switch
    • Pokemon pocket
    • FC 25 Ultimate Team
    • League of Legends
    • Tous les Forums
  • PC
  • PS5
  • Xbox Series
  • Switch 2
  • PS4
  • One
  • Switch
  • iOS
  • Android
  • MMO
  • RPG
  • FPS
En ce moment Genshin Impact Valhalla Breath of the wild Animal Crossing GTA 5 Red dead 2
Liste des sujets

[C] corruption de pile

dnob700
dnob700
Niveau 10
25 novembre 2009 à 14:36:03

J'ai un problème de corruption de pile que je n'arrivepas à comprendre. Mon code ressemble à ça :

struct table
{
size_t size, elem;
void** table;
};

  1. define chunk(n) struct {unsigned int hash; void* key[n]; void* data;}

static inline void add_elem(struct table table,unsigned int offset)
{
typedef chunk(3)* local_table;
local_table t = (local_table)table.table;
}

Et lorsque la deuxième ligne de la fonction add_elem est exécuté, la variable offset est corrompu (sa valeur change), Cf la sortie de GDB :

(gdb) print offset
$4 = 1030
(gdb) step
102 local_table t = (local_table)table.table;
(gdb) print offset
$5 = 1030
(gdb) step
103 offset = find_empty(3,t,table.size,offset);
(gdb) print offset
$6 = 6588144
(gdb)

(où l'on note que lorsqu'il y a la ligne 103 d'indiquée, c'est la ligne que je n'ai pas encore exécuté).

Sinon, est-ce que quelqu'un connait un bon outils d'analyse statique pour la gestion de la mémoire en C ?

chris_27
chris_27
Niveau 10
25 novembre 2009 à 15:05:48

J'ai pas trop le temps de regarder, mais :

as-tu demander son avis à l'ami valgrind ? Avec ces pointeurs dans tous les sens, c'est pas exclus que tu ais fait quelque chose de mal à un endroit.

dnob700
dnob700
Niveau 10
25 novembre 2009 à 15:34:22

je ne crois pas, parce que je n'alloue de la mémoire qu'à un seul endroit qui est très bien testé (je n'ai pas touché à la partie du code qui alloue de la mémoire depuis longtemps) et surtout, le problème se produit tout au début du programme (mais lors du deuxième appel à add_elem et non pas lors du premier, c'est vrai).

Ce qui est bizarre c'est que offset est sur la pile de la fonction certainement (je n'ai pas osé regarder du code assembleur) et que les deux opérations qui sont faites avant devrait être assez sûr.

dnob700
dnob700
Niveau 10
25 novembre 2009 à 16:08:30

horrible : valgrind m'a dit ça :

==11684== Use of uninitialised value of size 8
==11684== at 0x40A075: add_elem3 (table.h:103)
==11684== by 0x40A6D0: alloc_known (alloc.c:101)
==11684== Uninitialised value was created by a stack allocation
==11684== at 0x409E6C: add_elem3 (table.h:98)

la ligne 103 est l'appel de fonction qui ne va pas (deux posts plus heut) et la ligne 98 est l'entrée de la fonction. Alors j'ai remplacé mon code par ça, pour savoir quelle est la donnée qui n'est pas initilisé (valgrind ne me semble pas très verbeux, en même temps je découvre) par ça :

size_t s = table.size;
unsigned int o = offset;
offset = find_empty(3,t,s,o);

qui devrait avoir exactement la même sémantique (mais bon, je compile sans optimisation donc c'est sûr que ça va être compilé différemment), et là, paf, plus d'erreur avec valgrind, et plus de segfault non plus (mon programme ne fonctionne quand même pas (qu'est ce que je déteste le C...)).

Mais c'est un comportement que je n'aime pas trop. Quelqu'un aurait une idée de ce qui peut se passer avec ce code ? (et sinon, je vais regarder l'assembleur, mais j'aimerais mieux pas).

godrik
godrik
Niveau 30
25 novembre 2009 à 19:21:11

dnob, je manque de temps aujourd'hui. Mais c'est thanksgiving demain donc je jetterai un oeil.

dnob700
dnob700
Niveau 10
25 novembre 2009 à 22:14:11

Bon, je crois avoir un peu compris ce qui se passe et j'ai pu contourner le problème.

J'avais besoin de "template", donc j'ai utilisé ça http://gcc.gnu.org/onlinedocs/gcc-3.3.1/gcc/Statement-Exprs.html#Statement%20Exprs avec des macro (ce qui est une des fonctionnalité de GCC que j'aime bien, même si ça manque terriblement de sûreté). Et manifestement il y a des trucs bizarre qui se passaient avec la porté de mes variables qui étaient déclaré à l'intérieur de ces blocs lorsque je m'en servais comme d'une valeur de retour.

Donc là je passe en paramètre aux macro la variables qu'il faut modifier, plutôt que d'avoir une valeur de retour et je n'ai plus de problème (même si je ne comprend pas très bien ce qui se passait).

Et aussi, j'interprétais mal l'affichage de GDB (que je n'ai pas trop non plus l'habitude d'utiliser). Mais quand il affiche par exemple :
int a = f(b);

Si f est une fonction c'est qu'on n'a pas encore exécuté la ligne, si f est une macro alors elle a déjà été exécuté. C'est bizarre, mais j'ai vraiment l'impression que c'est ce qu'il fait, et comme il n'est pas capable de faire du pas à pas à l'intérieur d'une macro, j'ai mis du temps à me rendre compte que la corruption apparaissait après l'exécution de la macro et pas avant.

En tout cas merci à vous deux (je n'aurais pas pensé à utiliser valgrind et c'est ça qui m'a mis sur la piste).

_skip
_skip
Niveau 10
26 novembre 2009 à 08:08:04

Je me demande si y'a assez de choses qui s'appellent *table* dans ce code. Perso j'ai des doutes... Ca te gêne pas en lisibilité?

dnob700
dnob700
Niveau 10
26 novembre 2009 à 10:01:55

En lisibilité non, mais ça m'a donné des erreurs surprenante, parce que évidemment, si tu as une macro de ce genre (évidemment, pas aussi trivial) :

  1. define foo(table) table.table

Alors les deux tables sont remplacées par l'argument et le compilo te sort une erreur de genre l'objet bidule n'a pas de membre bidule. C'est sûr que c'est une limitation des macro en C (mais vu qu'on ne peut pas paramétrer des fonctions à la compilation, ou en tout cas, je n'ai pas trouvé de méthode élégante pour ça. Donc bon, il y a moins de tables maintenant.

Sous forums
  • Aide à l'achat Mac
  • Création de Jeux
  • Linux
  • Création de sites web
  • Programmation
  • Internet
  • Steam Deck
  • Macintosh
  • Hardware
La vidéo du moment