Question

Le deuxième appel à strcat ici génère une erreur de segmentation, pourquoi?

#include <unistd.h>
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>  
#include <pthread.h>

int main (int argc, char * argv[])
{
         char command[250];

         //if(scanf("%199s", command) == 1)

            gets(command);
            puts(command);

         int pipeIntId; 

         char whitespaceseparator[2]=" ";

         char pidstring [30];

         int pid= getpid(); 

         sprintf(pidstring,"%d", pid);

         char * whitespace_and_pid;

         whitespace_and_pid = strcat(whitespaceseparator,pidstring);  


         char * command_and_pid; 

         command_and_pid=strcat(command,whitespace_and_pid); // here's the problem, I guess


          if((mkfifo("pipe"/*pipeName*/,0666))==-1) 
          {
              perror("error creating pipe 1");
          exit(1);
          }

         if((pipeIntId=open("pipe",/*pipeName*/O_WRONLY))==-1)
         {
          perror("error creating pipe 2");
          exit(1);
         }


         int written;

         written=write(pipeIntId,command_and_pid,250); // send the command + the pid


         close(pipeIntId);

    return 0;
}
Était-ce utile?

La solution

J'ai essayé votre code, et voir aussi la segfault sur la deuxième strcat(). J'ai trouvé que command[250] est attribué immédiatement après whitespaceseparator[2] sur la pile sur mon système:

(gdb) p &whitespaceseparator 
$1 = (char (*)[2]) 0xbf90acd4
(gdb) p &command
$2 = (char (*)[250]) 0xbf90acd6

par exemple. (Ici command commence "foo..."), les choses sont layed comme ceci:

 whitespaceseparator
  |
  |      command
  |       |
  v       v
+---+---+---+---+---+---+---+---+
|' '| 0 |'f'|'o'|'o'|'.'|'.'|'.'| ...
+---+---+---+---+---+---+---+---+

Je ne peux pas garantir que la même chose se passe sur votre système (mise en page de la population locale sur la pile peut varier même entre les différentes versions du même compilateur), mais il semble probable. Sur le mien, voici exactement ce qui se passe:

Comme d'autres l'ont déjà dit, strcat() ajoute la seconde chaîne à la première (et le résultat sera égal au premier argument). Ainsi, la première strcat() déborde whitespaceseparator[] (et retourne whitespaceseparator comme whitespace_and_pid):

+---+---+---+---+---+---+---+---+
|' '|'1'|'2'|'3'|'4'| 0 |'.'|'.'| ...
+---+---+---+---+---+---+---+---+

Le second strcat() essais pour ajouter whitespace_and_pid (== whitespaceseparator) de la chaîne à command. Le premier caractère de la copie remplace la terminaison 0 de la chaîne à command:

  |    ===copy===>    |
  v                   v
+---+---+---+---+---+---+---+---+
|' '|'1'|'2'|'3'|'4'|' '|'.'|'.'| ...
+---+---+---+---+---+---+---+---+

La copie continue ...

      |    ===copy===>    |
      v                   v
+---+---+---+---+---+---+---+---+
|' '|'1'|'2'|'3'|'4'|' '|'1'|'.'| ...
+---+---+---+---+---+---+---+---+

          |    ===copy===>    |
          v                   v
+---+---+---+---+---+---+---+---+
|' '|'1'|'2'|'3'|'4'|' '|'1'|'2'| ...
+---+---+---+---+---+---+---+---+

et continuer la copie " 1234 1234 1234" ... jusqu'à ce qu'il tombe à la fin de l'espace d'adressage du processus, à quel point vous obtenez une erreur de segmentation.

Autres conseils

strcat ne fait pas ce que vous pensez. Il modifie la chaîne pointée par son premier paramètre. Dans ce cas, cette chaîne de caractères est contenue dans une matrice de 2 octets, qui est donc dépassé.

Pour éviter les erreurs dépassement de mémoire tampon, mais l'utilisation strcat vous devriez utiliser la fonction strncat.

Votre GARDERA aurait pu ajouter suffisamment de caractères déjà pour provoquer un comportement non défini à environ tout moment.

whitespaceseparator n'est pas assez grand pour contenir la chaîne chaînés, de sorte que vous causez un comportement non défini.

Utilisation gets est normalement désapprouvée aussi.

strcat est généralement dangereuse car elle peut heureusement des tampons de dépassement, comme il le fait dans votre cas.

D'abord, whitespaceseparator est seulement deux octets grand? Êtes-vous sûr que ce que vous voulez? Et vous concaténer pidstring à elle? Je pense que vous avez les arguments mélangés.

En général si, strcat va provoquer des plantages difficiles à debug si vous n'êtes pas très prudent avec vos tailles de tampon. Il existe des alternatives plus sûres.

« concaténation String » est un idiome que vous devriez abandonner lors de l'apprentissage C. Non seulement il conduit à beaucoup de bugs avec des tampons débordement; il est aussi super inefficace. Dans votre code, vous pouvez simplement avoir inclus l'espace dans la chaîne de format snprintf (vous devriez l'utiliser à la place de sprintf).

Chaque fois que possible, essayez d'assembler une chaîne entièrement en une seule étape à l'aide snprintf. Cette consolide toute la longueur de la mémoire tampon de vérification en un seul endroit et il est vraiment difficile de se tromper. Vous pouvez également appeler snprintf avec un argument 0 taille pour obtenir la longueur que la chaîne combinée serait, afin de savoir quelle taille à allouer, si la taille de la sortie ne soit pas connue à l'avance (vous devez allouer un octet de cette longueur de telle sorte que la terminaison null ne tronque pas votre sortie).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top