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

답변

4

코드를 시도했으며 두 번째 부분의 segfault도 참조하십시오. strcat().

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

예를 들면 : 나는 command[250] 내 시스템에 스택에 whitespaceseparator[2] 후 즉시 할당되는 것을 발견 (여기 command"foo..." 시작), 물건이처럼 누워있다 :

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

내가 같은 심지어 같은 컴파일러의 다른 버전과 다를 수 있습니다 시스템에 스택에 지역 주민의 (레이아웃을 어떻게 보장 할 수 없습니다), 그러나 그것은 아마 보인다. 광산에서 여기 정확히 무슨 일이 일어나는가 :

다른 사람들이 말했듯이, strcat()은 두 번째 문자열을 첫 번째 문자열에 추가합니다 (결과는 첫 번째 인수와 동일합니다). 그래서 첫 번째 strcat()whitespaceseparator[]을 오버 플로우 (그리고 whitespace_and_pidwhitespaceseparator를 반환) :

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

두 번째 strcat() 시도가 command에서 문자열 whitespace_and_pid (== whitespaceseparator)를 추가 할 수 있습니다. 이 떨어져 떨어질 때까지 ...

| ===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" 복사를 계속합니다 : 복사의 첫 번째 문자는 command에서 문자열의 종료 0을 덮어 쓰게됩니다 프로세스 주소 공간의 끝 부분에서 segfault를 얻습니다.

+0

+1 디버거를 작동 시키는데 좋은 설명입니다. –

1

gets 호출이 언제든지 정의되지 않은 동작을 유발할만큼 충분한 문자를 추가했을 수 있습니다.

3

strcat 당신이 생각하는대로하지 않습니다. 첫 번째 매개 변수가 가리키는 문자열을 수정합니다. 이 경우 해당 문자열은 2 바이트 배열에 포함되므로 오버런됩니다.

+0

아, 여기에서 확인했습니다. http://www.thinkage.ca/english/gcos /expl/c/lib/strcat.html. 처음 실행될 때 왜 작동하는지 궁금합니다. – andandandand

+0

처음 실행될 때 "작동"하지 않는다고 생각합니다.'pidstring'을'whitespaceseparator'의 끝에 복사하는 것은 정의되지 않은 행동입니다. 반드시 충돌이 반드시 발생하는 것은 아닙니다. Matthew의 대답은 당신이 생각하는 선상에서 충돌을 보게되는 이유에 대해 매우 그럴듯한 설명을하고 있습니다. –

+0

아니요,이 케이스를 공백 분리 기호와 함께 사용하는 것은 아닙니다. 이 함수는 충분한 크기의 버퍼로 처음 실행될 때 작동합니다.이 경우에는 whitepaceseparator의 크기를 큰 값으로 변경해도 작동하지 않습니다. – andandandand

1

whitespaceseparator은 연결 문자열을 포함 할 정도로 크지 않으므로 정의되지 않은 동작이 발생합니다.

gets을 사용하면 일반적으로 싫은 내게됩니다.

1

strcat은 일반적으로 버퍼가 오버런 될 수 있기 때문에 일반적으로 안전하지 않습니다.

우선 whitespaceseparator은 2 바이트 크기입니까? 그게 니가 원하는거야? 그리고 pidstring을 연결 하시겠습니까? 나는 당신이 인수가 섞여 있다고 생각합니다.

일반적으로 버퍼 크기에 매우 신중하지 않으면 strcat은 디버그하기 어렵습니다. 더 안전한 대안이 있습니다.

+0

등? 좋은 예가 될 것입니다. – anon58192932

2

버퍼 오버 플로우 오류를 방지하려면 strcat을 사용하려면 strncat 기능을 사용해야합니다.

1

"문자열 연결"은 C를 배울 때 삭제해야하는 관용구입니다. 오버플로 버퍼가있는 많은 버그가 발생할뿐만 아니라, 그것은 또한 매우 비효율적이다. 코드에서 snprintf 형식 문자열 (공백 문자는 sprintf 대신 사용해야 함)에 공백을 포함 할 수 있습니다.

언제든지 snprintf을 사용하여 한 단계로 문자열을 전체적으로 어셈블합니다. 이렇게하면 모든 버퍼 길이 검사가 한 곳으로 통합되어 오류가 발생하기가 어렵습니다. 을 0 크기의 인수로 호출하여 결합 된 문자열의 길이를 알아내어 할당 할 크기를 알아낼 수 있습니다. 미리 출력의 크기를 알 수없는 경우 (더 많은 바이트를 할당해야합니다. 널 종결자가 출력을 자르지 않도록이 길이).