2010-11-30 17 views
1

ここではstrcatへの2回目の呼び出しでセグメンテーションフォルトが生成されますが、なぜですか?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

私はあなたのコードを試しました。また、セグメンテーションを第2の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()は、最初に2番目の文字列を追加し(結果は最初の引数と同じになります)。だから、最初strcat()whitespaceseparator[]をオーバーフロー(及びwhitespace_and_pidとしてwhitespaceseparatorを返す):

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

strcat()試行をcommandで文字列にwhitespace_and_pid(== whitespaceseparator)を追加します。コピーの最初の文字は、commandで、文字列の終端0を上書きします:

| ===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"をコピーするに運びますプロセスのアドレス空間の終わりです。その時点でセグメンテーションが発生します。

+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

いいえ、私はそれがホワイトスペースセパレータでピッドストリングのこのケースを使用して動作しているわけではありません。これは、十分なサイズのバッファで初めて実行されたときに動作します。この場合、ホワイトスペースセパレータのサイズを大きな値に変更しても動作しません。例えば、 – andandandand

1

whitespaceseparatorは、連結された文字列を含むには十分ではないため、未定義の動作が発生しています。

getsを使用すると、通常は眉をひそめます。

1

strcatは、あなたのケースでそうであるように、バッファを楽しくオーバーランする可能性があるため、一般的に安全ではありません。

まず、whitespaceseparatorは2バイトだけですか?あなたはそれがあなたが望んでいると確信していますか?そしてpidstringをそれに連結しますか?私は議論が混ざっていると思います。

一般に、strcatは、バッファサイズにあまり注意を払わないと、デバッグが難しくなります。より安全な選択肢があります。

+0

?一例が素晴らしいだろう。 – anon58192932

2

バッファオーバーフローエラーを回避するには、strcatを使用するには、strncat機能を使用する必要があります。

1

"文字列連結"は、Cを学習するときに削除する必要があるイディオムです。オーバーフローするバッファで多くのバグが発生するだけでなく、超効率的でもありません。あなたのコードでは、スペースをsnprintfフォーマット文字列に含めることができます(sprintfの代わりに使用する必要があります)。

可能であれば、snprintfを使用して完全に1つのステップで文字列をアセンブルしてみてください。これにより、バッファ長チェックのすべてが1つの場所に集約され、間違ってしまうのが本当に難しくなります。 を0の引数を指定して呼び出すと、結合文字列の長さを取得して、出力のサイズが事前に分からない場合に割り当てるサイズを調べることができます。ヌルターミネータが出力を切り捨てないようにこの長さを指定します)。

関連する問題