2010-11-30 3 views
1

Второй звонок strcat здесь вызывает ошибку сегментации, почему?ошибка сегментации 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; 
} 
+0

Я решил проблему, используя первый ответ здесь http://stackoverflow.com/questions/308695/c-string-concatenation – andandandand 2010-11-30 01:20:07

ответ

4

Я пробовал ваш код, а также вижу 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" ... пока он не падает конец адресного пространства процесса, после чего вы получите segfault.

1

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

3

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

+0

О, я получил это отсюда http://www.thinkage.ca/english/gcos /expl/c/lib/strcat.html. Мне интересно, почему он работает в первый раз, когда он запускается. – andandandand 2010-11-30 01:19:22

+0

Я не думаю, что он «работает» при первом запуске: копирование `pidstring` до конца` whitespaceseparator` - это неопределенное поведение, что не означает, что он обязательно сбой сразу. В ответе Мэтью есть очень правдоподобное объяснение, почему вы видите крах в строке, которую вы указываете, предполагая, что ваша реализация делает то же самое, что и его. – 2010-11-30 02:26:04

+0

Нет, я не имею в виду, что он работает, используя этот случай pidstring с whitespaceseparator. Он работает, когда используется при первом запуске с достаточным размером буфера, изменяя размер whitespaceseparator в этом случае на большое значение, и он не будет работать. – andandandand 2010-11-30 03:29:50

1

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

Использование gets, как правило, нахмурилось.

1

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

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

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

2

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

1

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

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

Смежные вопросы