c probleme segment fault

a marqué ce sujet comme résolu.

bonjour quand je compile j'ai un segment fault

pourtant le tableau du main est directement modifier dans la fonction et non une copie non?

pouvez vous m'éclairer?

d'autant plus que quand je met la boucle for dans la fonction ça marche

 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
#include <stdio.h>
#include <stdlib.h>

void create (int tab[], int alloc)
{
    tab = malloc ((sizeof (int)) * alloc);
}

void destroy (int *t)
{
    free(t);
}

int main()
{
    int *tabmain = NULL;
    create (tabmain, 10);
    int i;
    for (i = 0; i < 10; i++)
    {
        tabmain[i] = i;
        printf("%d ",tabmain[i]);
    }
    destroy(tabmain);
    return 0;
}

Salut,

Je vais d’abord corriger ton code, puis t’expliquer l’ erreur.

 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
#include <stdio.h>

void create(int **tab, int alloc)
{
    *tab = malloc(sizeof(int) * alloc);
}

void destroy (int **t)
{
    free(*t);
}

int main(void)
{
    int *tabmain = NULL;
    create (&tabmain, 10);
    int i;
    for (i = 0; i < 10; i++)
    {
        tabmain[i] = i;
        printf("%d ",tabmain[i]);
    }
    destroy(&tabmain);
    return 0;
}

En fait, il faut réfléchir à ce que fais la fonction create. La fonction create doit modifier la valeur du pointeur qui lui est passée en paramètre et doit la faire pointer sur la zone mémoire allouée par malloc. Pour modifier la valeur du pointeur, il faut lui passer son adresse. D’où le double pointeur. J’imagine qu’il s’agit d’un exercice pour manier les pointeurs, parce que sinon ce code est beaucoup plus simple.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
int main(void)
{
    int *tabmain = calloc(10, sizeof(int));
    if(!tabmain)
        perror("Error malloc : ");
    else
    {
        int i;
        for (i = 0; i < 10; i++)
        {
            tabmain[i] = i;
            printf("%d ",tabmain[i]);
        }
        free(tabmain);
    }
    return 0;
}

Ici, j’utilise la fonction calloc et surtout je vérifie que l’allocation n’a pas échoué.

+1 -0

@Taurre,

Ton lien provoque une erreur 403.

Selon le man de malloc, il est indiqué ceci

By default, Linux follows an optimistic memory allocation strategy. This means that when malloc() returns non-NULL there is no guarantee that the memory really is available. In case it turns out that the system is out of memory, one or more processes will be killed by the OOM killer.

Cela dépendra donc de la/les plateformes sur la(es)quelle(s) on travaille…

Je ne pense pas que le fait que les choix effectués dans Linux rendent le fonctionnement de malloc complètement bancal et aberrant chez eux soit une bonne raison de ne pas tester le retour de malloc.

Ce que dit la norme c'est qu'après un malloc, tu reçois soit un pointeur nul, soit un pointeur vers une zone allouée de la bonne taille. Si ça ne fonctionne pas comme ça sur Linux, c'est après eux qu'il faut aller râler, mais ça ne dispense pas d'écrire du code correct.

Je me demande si c'est vraiment si "bancal et aberrant" que ça de déléguer par défaut la gestion des erreurs OOM entièrement à l'OS plutôt qu'aux programmes utilisateurs… C'est un mécanisme de sécurité qui permet de hiérarchiser les processus lorsque le système tourne en conditions dégradées, pour ne pas pourrir les processus vraiment critiques en les incitant à se suicider pour rien lorsqu'un autre processus fait n'importe quoi avec la mémoire (donc correctement configuré ça limite un risque évident d'attaque par déni de service, entre autres).

Dans tous les cas ça ne dispense absolument pas de tester la valeur de retour de *alloc. Notamment parce que ce comportement de Linux est paramétrable, et que c'est à l'utilisateur de choisir de l'activer ou non, pas au développeur.

+0 -0

Je me demande si c'est vraiment si "bancal et aberrant" que ça de déléguer par défaut la gestion des erreurs OOM entièrement à l'OS plutôt qu'aux programmes utilisateurs…

nohar

Ben disons que quand la mécanique te retire tout capacité à dire que ton code qui est formellement correct fonctionnera comme tu l'as décrit dans ta documentation, j'ai du mal à trouver ça cohérent.

C'est un mécanisme de sécurité qui permet de hiérarchiser les processus lorsque le système tourne en conditions dégradées, pour ne pas pourrir les processus vraiment critiques en les incitant à se suicider pour rien lorsqu'un autre processus fait n'importe quoi avec la mémoire (donc correctement configuré ça limite un risque évident d'attaque par déni de service, entre autres).

nohar

Ce qui est critiquable à mon sens, c'est le fait que l'algorithme soit optimiste. Filer un pointeur à l'utilisateur en lui disant "t'inquiètes il est valide" et lui péter une segfault dans la bouche dès qu'il l'utilise, c'est franchement pas terrible pour la confiance que peut avoir le développeur dans son environnement d'exécution.

Ben disons que quand la mécanique te retire tout capacité à dire que ton code qui est formellement correct fonctionnera comme tu l'as décrit dans ta documentation, j'ai du mal à trouver ça cohérent.

La mécanique ne te retire rien du tout : ton programme fonctionne tel qu'il est décrit par ta doc. Simplement l'OS donne à l'utilisateur un mécanisme de contrôle supplémentaire au travers de ce hook, qui est documenté, paramétrable et désactivable de plusieurs façons différentes (y compris pid-wise), pour gérer le cas très concret où le système est sur le point de se casser la gueule et où il faut éviter de perdre une prod, là, tout de suite, dans la milliseconde.

C'est pas une question de confiance que le développeur peut avoir dans l'OS ou non, lui il a une norme à respecter et rien à se reprocher du moment qu'il la respecte. C'est aux ops de se poser la question, et pour un admin sys, le fait de savoir comment fonctionne le mécanisme d'OOM sous Linux pour configurer son système en connaissance de cause, c'est juste la base.

Edit :

Ah, et non, tu ne te prends pas une segfault dans la tronche si la mémoire n'est pas dispo. Tu te fais juste tuer par l'OOM killer si, effectivement, il n'y a plus de mémoire et si tu n'es pas assez prioritaire pour survivre à l'apocalypse.

+0 -0

re bonjour, je me permet de rouvrir ce topic car il concerne le mème code, alors voila j'éssai de le comprendre au niveau de la mémoire, j'ai donc pris mon débogueur préféré visual studio et là tout c'est éclaircie (enfin j’espère) donc apparemment l'adresse d'un pointeur comme "&ptr" serai de type int* * et ptr de type int * ? donc si on envoi ces données en paramètres à une fonction il faut que la variable qui la reçoit soit du même type ?

1
2
3
4
5
-       &tabmain    0x001ffa3c {0x00329fa0 {0}} int * *
-                     0x00329fa0 {0}            int *
                         0                          int
-       
                 tabmain    0x00329fa0 {0}                  int *
+0 -0

[…] donc si on envoi ces données en paramètres à une fonction il faut que la variable qui la reçoit soit du même type ?

mikoko

Pas forcément du même type, mais la valeur envoyée doit pouvoir être reçue par le paramètre de destination. Ainsi, par exemple, assigner une valeur de type pointeur sur char à un paramètre de type pointeur sur int est incorrect. Cela devient correct si le paramètre est également de type pointeur sur char (ou s'il est un pointeur sur void puisqu'il s'agit dans ce cas d'un pointeur générique).

+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