Tout d'accord toutes mes excuses pour la longueur du post, mais j'ai ce problème depuis un bon bout de temps sans en voir la solution.
j'ai un problème lié à de l'allocation mémoire par un malloc, mais aussi lié au système et à mes distribs par les limitations soft (ulimit).
Je m'explique : j'ai 3 distribs
- Redhat 8.0, noyau 2.4.18-14, glibc-2.2.93-5, aucune limite soft
- Mandrake 10.1, noyau 2.6.8.1-12, glibc-2.3.3-21, limité en stack size à 8 Mo
- Red Hat Enterprise 3, noyau 2.4.21-27.0.2, glibc-2.3.2-95.33, limité en stack size à 10 Mo.
J'ai le code C suivant (pas parfait):
#include stdlib.h
#include malloc.h
#include stdio.h
int main(void) {
unsigned int base,*decalage,longueur;
unsigned int* addr; int i;
base = 134835592;
longueur = 40000;
addr = malloc(longueur * sizeof(base));
decalage=(addr-base) ;
printf("\ndecalage = %u = %d et base = %u \n",decalage,decalage,base);
printf("decalage = 0x%x et base = 0x%x \n",decalage,base);
printf("addr = %u = %d\n",addr,addr);
printf("addr = 0x%x\n",addr);
printf("&addr = %u = %d\n",&addr,&addr);
printf("&addr = 0x%x\n",&addr);
for (i=0;i<longueur;i+=1024) {addr[i]=i;}
}
En exécutant ce code sur les 3 distribs, j'ai 2 types de résultats différents. les distribs 1 et 2 d'un coté, la 3 de l'autre.
- distrib 1 :
decalage = 534485480 = 534485480 et base = 134835592
decalage = 0x1fdb99e8 et base = 0x8096d88
addr = 1073827848 = 1073827848
addr = 0x40015008
&addr = 3221222084 = -1073745212
&addr = 0xbffff2c4
- distrib 2 :
decalage = 535673320 = 535673320 et base = 134835592
decalage = 0x1fedb9e8 et base = 0x8096d88
addr = 1075015688 = 1075015688
addr = 0x40137008
&addr = 3221221700 = -1073745596
&addr = 0xbffff144
- distrib 3 :
decalage = 2535635432 = -1759331864 et base = 134835592
decalage = 0x9722b9e8 et base = 0x8096d88
addr = 3074977800 = -1219989496
addr = 0xb7487008
&addr = 3221214884 = -1073752412
&addr = 0xbfffd6a4
Sauf que quand je supprime la limitation sur la stacksize de la distrib 3, je me retrouve avec les mêmes types de résultats pour toutes les distribs (je rappelle que la distrib 2 a elle aussi une limite sur la stacksize sans donner de résultats différents de la distrib 1.)
- distrib 3 :
decalage = 535775720 = 535775720 et base = 134835592
decalage = 0x1fef49e8 et base = 0x8096d88
addr = 1075118088 = 1075118088
addr = 0x40150008
&addr = 3221222068 = -1073745228
&addr = 0xbffff2b4
Par même type de résultats, je veux dire que l'allocation malloc se fait dans les environs de la même adresse. Ceci est important, car les adresses représentées non signées sont négatives, ce qui peut entraîner des débordements lorsqu'elles sont utilisées en valeur absolue (c'est pas moi qui programme !)dans une autre partie de code.
Détail amusant : lancé plusieurs fois, le code donne exactement les mêmes résultats pour les distribs 1 et 2 ; pour la distrib 3 (limitée ou pas) les résultats diffèrent à chaque exécution.
Bref, mes questions sont les suivantes :
- quelle est le lien entre la stacksize et le malloc ?
- pourquoi la limitation stacksize n'a pas d'influence sur la distrib 2 alors qu'elle en a sur la distrib 3 ?
PS : si quelqu'un pouvait m'expliquer comment on fait "<" et ">" ça m'arrangerait, j'y suis pas arrivé. Merci.
# Patches de sécurité
Posté par Nicolas Bernard (site web personnel) . Évalué à 6.
Je pense que la distrib 3 doit utiliser des patches de sécurité (genre PaX ou grsec) qui "randomizent" la mémoire, c'est à dire mettent la pile et les autres segments à des endroits aléatoires afin d'offrir une sécurité contre l'exploitation de failles dans les programmes (cela rend les calculs d'adresse difficiles pour les pirates).
# Re : Perdu dans la mémoire (malloc, stack, heap et système)
Posté par adibou . Évalué à 2.
$ cat foo.c
#include <stdio.h>
int main()
{
printf("%d %d\n", sizeof(void*), sizeof(int));
}
sur une archi 64 bits :
$ gcc foo.c && ./a.out
8 4
sur une archi 32 bits :
$ gcc foo.c && ./a.out
4 4
[^] # Re: Re : Perdu dans la mémoire (malloc, stack, heap et système)
Posté par bob_razowski . Évalué à 1.
Mais mon programme est appelé par un programme fortran, qui passe des adresses à ma routine C. Et si je ne me trompe pas, ces adresses sont des integer. J'aurai pour ma part préféré des unsigned int.
Donc comme j'ai des int, ma variable "decalage" est donc prise, en retour de ma routine C, dans le fortran comme un integer. Et peut donc être négative. Aucun problème si ce n'est que le traitement mémoire se fait derrière sur sa valeur absolue : on tape donc dans des zones mémoires aléatoires.
Le mec qui a codé le fortran ne s'y attendait surement pas.
[^] # Re: Re : Perdu dans la mémoire (malloc, stack, heap et système)
Posté par pierthi . Évalué à 3.
> Mais mon programme est appelé par un programme fortran
Euh, rassure-moi tu voulais dire "ma bibliothèque de fonction est appelé par un programme fortran", parce que l'espace d'adressage d'un processus à l'autre est complétement différent.
> Ces adresses sont des integer. J'aurai pour ma part préféré des unsigned int.
Euh, ce n'est qu'une question de convention. Un simple cast, et hop, tes int se transforment en unsigned int :
unsigned int i = (unsigned int) -1;
printf ("i = %u\n", i); // 4294967295
Ou utiliser un entier signé comme une adresse mémoire :
int i;
long addr = (long) &i; // là tu as une adresse sour forme d'entier signé
((int *)addr)[0] = 1234; // Positionne i à 1234
> Donc comme j'ai des int [...] zones mémoires aléatoires.
Ou tu débutes en programmation, ou tu expliques super mal, ou tu cherches à faire compliquer quand on peut faire simple. De ce que j'ai compris, tu as un programme fortran, qui te passes une zone mémoire sous forme d'entier (signé ou pas, il ne devrait pas y avoir de problème).
Toi tu veux allouer un nouveau buffer et renvoyer au programme fortran l'adresse de ce nouveau buffer sous forme d'offset par rapport à l'ancien (si ma mémoire est bonne, Fortran ne gère pas l'allocation dynamique).
Pourquoi ne pas simplement retourner l'adresse du buffer sous forme d'entier (signé ou pas, on s'en fous) ?
Dans tous les cas, n'espère surtout pas avoir une valeur constante dans ta variable "decalage".
[^] # Re: Re : Perdu dans la mémoire (malloc, stack, heap et système)
Posté par bob_razowski . Évalué à 1.
Derrière ce problème anodin, il y a un gros code industriel (oui oui, mais pas connu du public).
[^] # Re: Re : Perdu dans la mémoire (malloc, stack, heap et système)
Posté par adibou . Évalué à 3.
dc dans ton prog, la taille de addr n'est pas focement la taille d'un int (ce que tu utilise par le %d des printf), ni celle dun unsigned int (%u), sur mon athlon 32 bits, c'est le cas, mais c'est pas forcement une verite absolue...
enfin, comme dis dans un autre commentaire, un cast et ca repart... le codage de l'adresse n'intervient pas, il suffit de bien utiliser la valeur (dc connaitre le codage intervient en fait ^^ )
ensuite, il faut aussi voir que l'adresse que tu obtiens avec le malloc, c'est une adresse "virtuelle", plusieurs processus peuvent obtenir une meme adresse, et ecrire a des endroits differents dans la memoire, mais a mon avis, ca ne concerne en rien ton probleme, c'est juste au noyau de se debrouiller avec...
# Hum
Posté par pierthi . Évalué à 3.
À vrai dire, je ne vois pas quel est ton problème. Les valeurs de malloc() changent entre plusieurs distributions ? Ben, moi je dirais que les valeurs devraient changer même lorsque tu testes sur le même système.
À part quelques besoins ultra pointus (canaux DMA d'une carte d'acquisition par exemple), il n'y a aucun intérêt à allouer de la mémoire à adresse fixe. Qui plus est, la seule certitude que tu peux avoir avec malloc(), c'est soit d'avoir une valuer nulle (et encore sous Linux ton process sera flingué d'office) ou soit une valeur différente de 0. Tout le reste n'est qu'effet de bord ultra suicidaire à exploiter, lié à je ne sais trop quel coïncidence entre l'ordonnanceur du système et la pagination mémoire.
Bref, les résultats que tu obtiens me semblent normaux.
[^] # Re: Hum
Posté par bob_razowski . Évalué à 0.
Le test lancé plusieurs fois de suite me donne les mêmes adresses.
Et pareil, ma Ubuntu est limitée en stacksize à 8 Mo. Si j'enlève cette limite, le test donne des adresses différentes de celles qu'elles étaient avec la limitation. Et de nouveau, plusieurs tests à la suite donnent des adresses identiques.
Je suis d'accord sur le fait que les valeurs peuvent être différentes d'une distrib à une autre. D'ailleur je ne le remettait pas en cause. La chose qui me gène c'est une telle disparité dans les adresses : d'un coté j'ai : 0x40015008 (1), 0x40137008 (2), 0x40157008 (Ubuntu unlimited), 0x40150008 (3 unlimited) et de l'autre j'ai : 0xb7e82008 (Ubuntu limited) et 0xb7487008 (3 limited).
Je n'arrive pas à avoir une explication de ce phénomène (surtout entre limited et unlimited).
[^] # Re: ??! \_O< ...
Posté par pierthi . Évalué à 3.
Parce que tu voudrais que ces adresses soient identiques d'un lancement à l'autre ?
Bon, je te le dis tout de suite : c'est impossible. C'est le cas pour quelques uns de tes tests, mais ça tiens plus du coup de chance, certainement lié au fait que tu venais de lancer ton programme plusieurs fois de suite et le fait que la pagination a *tendance* à utiliser les mêmes schéma d'adresse (0x8...... ou 0xb....).
Je persiste à dire, que tes résultats sont tout à fait normaux.
[^] # Re: ??! \_O< ...
Posté par bob_razowski . Évalué à 1.
Mais pourquoi la délimitation sur la stacksize change t-elle autant les valeurs ?
Surtout que pour la Mandrake 10.1, limité ou pas c'est les mêmes résultats.
Je ne suis pas hyper calé en mémoire, mais il me semble que la stack et le malloc c'est pas au même endroit...
# comprends rien ...
Posté par Vivi (site web personnel) . Évalué à 3.
elle sort d'où ta valeur de base ? pourquoi tu la soustrait à addr ? t'espère obtenir quoi ?
adresses représentées non signées sont négatives
si c'est non signé, ça risque pas d'être négatif !
[^] # Re: comprends rien ...
Posté par bob_razowski . Évalué à 1.
C'est signé que je voulais dire. C'est le fait qu'en étant int, mon adresse puisse être négative, et que retraitée ensuite dans le fortran en valeur absolue on pointe alors sur la mauvaise zone allouée.
En fait "base" est une adresse donnée par la routine fortran, et "decalage" sert ensuite dans le fortran à manipuler la mémoire à partir de "base".
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.