ошибка сегментации strcat - PullRequest
1 голос
/ 30 ноября 2010

Второй вызов strcat здесь вызывает ошибку сегментации, почему?

#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;
}

Ответы [ 7 ]

4 голосов
/ 30 ноября 2010

Я попробовал ваш код, и также вижу segfault на втором strcat(). Я обнаружил, что command[250] выделяется сразу после whitespaceseparator[2] в стеке моей системы:

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

например. (здесь command начинается "foo..."), все выглядит так:

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

Я не могу гарантировать, что то же самое происходит в вашей системе (расположение локальных стеков в стеке может отличаться даже для разных версий одного и того же компилятора), но это кажется вероятным По моему, именно так и происходит:

Как уже говорили другие, strcat() добавляет вторую строку к первой (и результат будет равен первому аргументу). Итак, первое strcat() переполняется whitespaceseparator[] (и возвращает whitespaceseparator как whitespace_and_pid):

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

Второй strcat() пытается добавить whitespace_and_pid (== whitespaceseparator) к строке в command. Первый символ копии перезапишет завершающий 0 строки в command:

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

Копия продолжается ...

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

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

и будет продолжать копирование " 1234 1234 1234" ... до тех пор, пока оно не упадет в конец адресного пространства процесса, после чего вы получите ошибку сегмента.

3 голосов
/ 30 ноября 2010

strcat не делает то, что вы думаете.Он изменяет строку, на которую указывает ее первый параметр.В этом случае эта строка содержится в 2-байтовом массиве, который поэтому переполняется.

2 голосов
/ 30 ноября 2010

Чтобы избежать ошибок переполнения буфера, но используйте strcat, вам следует использовать функцию strncat.

1 голос
/ 30 ноября 2010

«Конкатенация строк» ​​- это идиома, которую вы должны отбросить при изучении C. Это не только приводит к множеству ошибок с переполнением буферов; это также супер неэффективно. В вашем коде вы могли просто включить пробел в строку формата snprintf (вы должны использовать его вместо sprintf).

По возможности, попытайтесь собрать строку целиком за один шаг, используя snprintf. Это объединяет все проверки длины буфера в одном месте и делает очень трудным ошибиться. Вы также можете вызвать snprintf с аргументом размера 0, чтобы получить длину, которая будет объединенной строкой, чтобы выяснить, какой размер выделить, если размер вывода заранее неизвестен (вам следует выделить еще байт этой длины, чтобы нулевой терминатор не обрезал ваш вывод).

1 голос
/ 30 ноября 2010

strcat, как правило, небезопасно, поскольку может успешно переполнять буферы, как в вашем случае.

Прежде всего, whitespaceseparator имеет размер только два байта? Вы уверены, что это то, что вы хотите? И вы присоединяете pidstring к этому? Я думаю, что вы перепутали аргументы.

В целом, strcat вызовет сбои, которые трудно отладить, если вы не очень осторожны с размерами буфера. Есть более безопасные альтернативы.

1 голос
/ 30 ноября 2010

whitespaceseparator недостаточно большой, чтобы содержать объединенную строку, поэтому вы вызываете неопределенное поведение.

Использование gets также обычно вызывает недовольство.

1 голос
/ 30 ноября 2010

Ваш вызов get уже мог добавить достаточно символов, чтобы вызывать неопределенное поведение примерно в любое время.

...