Partage
  • Partager sur Facebook
  • Partager sur Twitter

Problème strtok_r() erreur de segmentation.

Programme C sous LINUX

Sujet résolu
10 mai 2021 à 5:41:28

.

-
Edité par Rachid-Bellaali 17 mai 2021 à 19:12:14

  • Partager sur Facebook
  • Partager sur Twitter

Bellaali Abderrachid

10 mai 2021 à 6:30:56

Bonjour,

Rachid-Bellaali a écrit:

[...]

J’ai une « Erreur de segmentation (core dumped) » qui proviens je pense de la fonction strtok_r() mais que je n’arrive pas à corriger ;(

«je pense» ? Tu n'en es pas certain ? Tu n'as pas utilisé de debuger ou de memory profiler pour t'en assurer ?????

Rachid-Bellaali a écrit:

[...]
Je dois utiliser strtok_r() parce que j’ai envie d’exécuter chaque ligne donc pour découper à chaque "\n" (saut de ligne).

Sais-tu que fgets fais exactement cela ? Enfin je dis ça je dis rien hein.

ah oui ... encore une chose : essaye de compiler avec les options qui te donnent un maximum d'indications sur ton code. Lorsque je prends ton bout de code et que je le fais j'obtiens ces warnings ⇒

$ gcc -Wall -Wextra -fanalyzer -o dumb dumb.c 
dumb.c:14:6: warning: return type of ‘main’ is not ‘int’ [-Wmain]
   14 | void main (int argc, char* argv[]) {
      |      ^~~~
dumb.c: In function ‘main’:
dumb.c:20:10: warning: unused variable ‘affichage’ [-Wunused-variable]
   20 |     char affichage[5]; // variable pour stocker les trucs avant de les afficher en stdout
      |          ^~~~~~~~~
dumb.c:19:9: warning: unused variable ‘qte’ [-Wunused-variable]
   19 |     int qte; // cmb de charactères ont été lus de popen_result
      |         ^~~
dumb.c: In function ‘my_popen’:
dumb.c:106:15: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
  106 |         while(quantite = read(pipefd[0], affichage, 5))
      |               ^~~~~~~~
dumb.c: In function ‘main’:
dumb.c:56:13: warning: use of NULL ‘saveptr’ where non-null expected [CWE-690] [-Wanalyzer-null-argument]
   56 |     ligne = strtok_r(contenu, "\n", saveptr); // on commence à couper le contenu par ligne
      |             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  ‘main’: events 1-12
    |
    |   22 |     if (argc == 1) { // au moins un argument
    |      |        ^
    |      |        |
    |      |        (1) following ‘false’ branch (when ‘argc != 1’)...
    |......
    |   27 |     fd = open(argv[1], O_RDONLY); // ouvrir le fichier shell
    |      |                   ~
    |      |                   |
    |      |                   (2) ...to here
    |   28 | 
    |   29 |     if (fd == -1) { // vérifier que l'ouverture a marché
    |      |        ~
    |      |        |
    |      |        (3) following ‘false’ branch (when ‘fd != -1’)...
    |......
    |   34 |     size_read = read(fd, contenu, CONTENT_SIZE); // lire contenu du fichier shell
    |      |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |                 |
    |      |                 (4) ...to here
    |   35 | 
    |   36 |     if (size_read == -1) { // si erreur lecture
    |      |        ~
    |      |        |
    |      |        (5) following ‘false’ branch (when ‘size_read != -1’)...
    |......
    |   40 |     else if (size_read == CONTENT_SIZE) { // si fichier plus grand que variable contenu
    |      |             ~
    |      |             |
    |      |             (6) ...to here
    |      |             (7) following ‘false’ branch (when ‘size_read != 2048’)...
    |......
    |   45 |     if(close(fd) == -1) { // on a fini de travailler avec le fichier shell, -1 si erreur
    |      |       ~~~~~~~~~~
    |      |       ||
    |      |       |(8) ...to here
    |      |       (9) following ‘false’ branch...
    |......
    |   50 |     contenu[size_read] = '\0'; // read n'ajoute pas \0 à la fin du string, donc on doit l'ajouter pour que le string soit bien formé
    |      |     ~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |                        |
    |      |                        (10) ...to here
    |      |                        (11) ‘saveptr’ is NULL
    |......
    |   56 |     ligne = strtok_r(contenu, "\n", saveptr); // on commence à couper le contenu par ligne
    |      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |             |
    |      |             (12) argument 3 (‘saveptr’) NULL where non-null expected
    |
In file included from dumb.c:7:
/usr/include/string.h:350:14: note: argument 3 of ‘strtok_r’ must be non-null
  350 | extern char *strtok_r (char *__restrict __s, const char *__restrict __delim,
      |              ^~~~~~~~
dumb.c: In function ‘my_popen’:
dumb.c:141:15: warning: use of NULL ‘saveptr2’ where non-null expected [CWE-690] [-Wanalyzer-null-argument]
  141 |         mot = strtok_r(ligne, " ", saveptr2);
      |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  ‘my_popen’: events 1-12
    |
    |   76 |     if (strlen(ligne) == 0)
    |      |        ^
    |      |        |
    |      |        (1) following ‘false’ branch...
    |......
    |   82 |     if (pipe(pipefd) == -1) { //créer le pipe et vérifier qu'il n'y a pas d'erreur
    |      |        ~~~~~~~~~~~~~
    |      |        ||
    |      |        |(2) ...to here
    |      |        (3) following ‘false’ branch...
    |......
    |   87 |     pid = fork(); // créer le processus fils
    |      |           ~~~~~~
    |      |           |
    |      |           (4) ...to here
    |   88 | 
    |   89 |     if( pid < 0 ) { //erreur dans le fork
    |      |       ~ 
    |      |       |
    |      |       (5) following ‘false’ branch (when ‘pid >= 0’)...
    |......
    |   94 |     else if ( pid > 0 ) //dans le parent
    |      |             ~
    |      |             |
    |      |             (6) ...to here
    |      |             (7) following ‘false’ branch (when ‘pid <= 0’)...
    |......
    |  131 |         int i = 0; // defini ici pour avoir accées en général !
    |      |             ~
    |      |             |
    |      |             (8) ...to here
    |  132 | 
    |  133 |         if (close(pipefd[0]) == -1) { //on écrit dans le fils, donc on ferme le pipe en lecture
    |      |            ~
    |      |            |
    |      |            (9) following ‘false’ branch...
    |......
    |  139 |         char **saveptr2 = NULL;
    |      |                ~~~~~~~~
    |      |                |
    |      |                (10) ...to here
    |      |                (11) ‘saveptr2’ is NULL
    |  140 | 
    |  141 |         mot = strtok_r(ligne, " ", saveptr2);
    |      |               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |               |
    |      |               (12) argument 3 (‘saveptr2’) NULL where non-null expected
    |
In file included from dumb.c:7:
/usr/include/string.h:350:14: note: argument 3 of ‘strtok_r’ must be non-null
  350 | extern char *strtok_r (char *__restrict __s, const char *__restrict __delim,
      |              ^~~~~~~~

Je n'ai pas lu ton code, mais la description de ton erreur et les indication du compilo me laissent à penser que tu n'as pas lu la doc de strtok_r ⇒ la partie de la man page qui t'intéresse (àmha) :

       On the first call to strtok_r(), str should point to the string to be parsed, and the value of *saveptr is  ignored  (but
       see  NOTES).  In subsequent calls, str should be NULL, and saveptr (and the buffer that it points to) should be unchanged
       since the previous call.


Edit: 
Bon j'ai parcouru ton code. Ça va, j'ai vu bien pire.
Donc si tu veux quelques remarques :

  • fais des fonctions !!!!!!
    fais des fonctions !!!!!!
    FAIS DES FONCTIONS !!!!!!

  • oublie les commentaires !!!
    aucun des commentaires sur les variables au début du main nesert à quoi que ce soit si le nom des variables est clair.
    chaque commentaire à côté des fonctions indique que l'appel et les quelques lignes qui suivent ont une logique à être ensemble … oublie les commentaires et fais des fonctions

  • la lecture du script pêche mais j'imagine que tu vas adapter ça

  • les exit c'est un peu … violent, mais à nouveau j'imagine que que tu vas modifier cela

  • et main … main est une fonction qui renvoie un int !!!! on n'est plus en 1975 !!! le disco est mort en même temps que les void main … ok ok, techniquement il n'est jamais mort … ^_^

  • et les commentaires dans le script ?

-
Edité par White Crow 10 mai 2021 à 7:41:23

  • Partager sur Facebook
  • Partager sur Twitter
10 mai 2021 à 9:27:19

Salut mercii pour tes conseils ! et j'ai trouvé mon erreur.
  • Partager sur Facebook
  • Partager sur Twitter

Bellaali Abderrachid

10 mai 2021 à 10:00:00

Qui est ? Parce que c'est toujours sympa de dire quelle était l'erreur et comment tu l'as résolue pour ceux qui vont lire ce sujet en ayant un problème similaire au tien …
  • Partager sur Facebook
  • Partager sur Twitter
18 mai 2021 à 1:07:20

@Rachid-Bellaali Bonsoir, on n'efface pas ses messages après avoir reçu de l'aide.

Je recopie ci après le message d'origine pour archive et ferme ce sujet.

Rachid-Bellaali a écrit:

Bonjour à tous, je débute en C et je suis entrain de crée un programme C sous LINUX qui reçoit en paramètre (via la ligne de commande) un shell script (shell file), c’est-à-dire un fichier contenant une suite de commandes shell.

Chacune des commandes du fichier doit être exécutée par un fils, qui renvoie les résultats au père via le pipe et le père affichera les résultats à l’écran.

J’ai une « Erreur de segmentation (core dumped) » qui proviens je pense de la fonction strtok_r() mais que je n’arrive pas à corriger ;(

Je dois utiliser strtok_r() parce que j’ai envie d’exécuter chaque ligne donc pour découper à chaque "\n" (saut de ligne).

Si quelqu'un pourrais m'aider ce serais gentil mercii.


Voici mon programme C :

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
 
#define CONTENT_SIZE 2048 // constante pour pouvoir la changer plus facilement
 
void my_popen(char ligne[]);
 
 
void main (int argc, char* argv[]) {
    int fd; // ça va contenir le fd du fichier à lire
    char contenu[CONTENT_SIZE]; // ça va contenir le contenu du fichier
    char* ligne; // ça va contenir que une ligne du fichier
    ssize_t size_read; // ça va contenir cmb de charactères ont été lus
    int qte; // cmb de charactères ont été lus de popen_result
    char affichage[5]; // variable pour stocker les trucs avant de les afficher en stdout
 
    if (argc == 1) { // au moins un argument
        printf("Pas assez d'arguments.\n");
        exit(0);
    }
 
    fd = open(argv[1], O_RDONLY); // ouvrir le fichier shell
 
    if (fd == -1) { // vérifier que l'ouverture a marché
        perror("Ouverture du fichier");
        exit(1);
    }
 
    size_read = read(fd, contenu, CONTENT_SIZE); // lire contenu du fichier shell
 
    if (size_read == -1) { // si erreur lecture
        perror("Lecture du fichier");
        exit(1);
    }
    else if (size_read == CONTENT_SIZE) { // si fichier plus grand que variable contenu
        printf("Le fichier est trop grand pour être executé.\n");
        exit(1);
    }
     
    if(close(fd) == -1) { // on a fini de travailler avec le fichier shell, -1 si erreur
        perror("Fermeture du fichier");
        exit(1);
    };
 
    contenu[size_read] = '\0'; // read n'ajoute pas \0 à la fin du string, donc on doit l'ajouter pour que le string soit bien formé
 
    //char* *saveptr : saveptr est un pointeur qui pointe vers un pointeur char qui lui pointe vers un char (cghar* -> c'est un string)
 
    char **saveptr = NULL;
 
    ligne = strtok_r(contenu, "\n", saveptr); // on commence à couper le contenu par ligne
 
 
    while(ligne != NULL) { // on va travailler tant qu'il y aura des lignes
         
        my_popen(ligne);
 
        ligne = strtok_r(NULL, "\n", saveptr); //on prend la ligne suivante et on récommence.
    }
 
    exit(0);
}
 
 
 
void my_popen(char ligne[])
{
    pid_t pid; //stocke le résultat du fork -> pid_t psk c le meilleur pour stocker le result du PID
    int pipefd[2]; //file descriptors pour intéragir avec le pipe (0 lecture, 1 écriture)
 
    if (strlen(ligne) == 0)
    {
        return ;
    }
 
 
    if (pipe(pipefd) == -1) { //créer le pipe et vérifier qu'il n'y a pas d'erreur
      perror("Problème création du Pipe().");
      exit(1);
    }
 
    pid = fork(); // créer le processus fils
 
    if( pid < 0 ) { //erreur dans le fork
      perror("Problème avec le Fork() !");
      exit(1);
    }
 
    else if ( pid > 0 ) //dans le parent
    {
        if (close(pipefd[1]) == -1) { //le parent lis, donc on ferme celui de ecriture
          perror("Problème avec fermeture Pipe() du parent !");
          exit(1);
        }
 
        // la ont va lire ce qui est dans le pipe
        char affichage[5];
        ssize_t quantite;
 
        // enregistre le resultat du read dans la variable...
        while(quantite = read(pipefd[0], affichage, 5))
        {
            if (quantite == -1){
              perror("Probleme avec le Read() !");
              exit(1);
            }
 
            if (write(STDOUT_FILENO, affichage, quantite) == -1){ // ecrit dans STDOUT, quantite (var) de caractere d'affichage
              perror("Probleme avec le Write() !");
              exit(1);
            }
        }
 
        if (close(pipefd[0]) == -1) {// on ferme le pipe côté parent
          perror("Problème fermeture Pipe() du parent !");
          exit(1);
        }
 
      return; // psk void
    }
 
 
    else //dans le fils
    {
        char* paramsList[64];
        int i = 0; // defini ici pour avoir accées en général !
 
        if (close(pipefd[0]) == -1) { //on écrit dans le fils, donc on ferme le pipe en lecture
           perror("Problème fermeture Pipe() du fils !");
           exit(1);
        }
 
        char* mot; // pointeur vers un caractère
        char **saveptr2 = NULL;
 
        mot = strtok_r(ligne, " ", saveptr2);
 
        //printf("Fils : %s\n", ligne);
 
        while(mot) {
             
            paramsList[i] = mot;
 
            mot = strtok_r(NULL, " ", saveptr2);
 
            i++;
        }
 
        paramsList[i] = NULL; //les fonctions execv demandent que la liste de paramètres termine par NULL.
 
        //printf(" params : %s %s %s \n", paramsList[0], paramsList[1], paramsList[2]);
 
        // si pas d'erreur avec dup2 -- file numéro 0
        if (dup2(pipefd[1], STDOUT_FILENO) == -1) { // rediriger tous ce qui est dans le STD-OUT dans pipeFd[1]
          perror("Probleme avec dup2() !");
          exit(1);
        }
 
        if (execvp(paramsList[0], paramsList) == -1) {
          perror("Probleme avec Execvp() !");
          exit(1);
        }
 
        if (close(pipefd[1]) == -1) { //on ferme le pipe côté fils
          perror("Problème fermeture Pipe() du fils !");
          exit(1);
        }
 
      exit(0);
    }
 
}


et mon ShellScript (attention il faut lui donner la permission x pour être exécuter)

#!/bin/sh
mkdir repertoire
touch repertoire/monFile
echo "Hello word"





  • Partager sur Facebook
  • Partager sur Twitter