1

ここへの 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;
}
4

7 に答える 7

4

私はあなたのコードを試しましたが、2 番目の 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()、2番目の文字列を最初の文字列に追加します(結果は最初の引数と等しくなります)。したがって、最初のstrcat()オーバーフローwhitespaceseparator[](および として返さwhitespaceseparatorれますwhitespace_and_pid):

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

2 番目は、文字列 at に(== )strcat()を追加しようとします。コピーの最初の文字は、次の文字列の末尾の 0 を上書きします。whitespace_and_pidwhitespaceseparatorcommandcommand

  |    ===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"続けます...プロセスアドレス空間の最後から落ちるまで、その時点でセグメンテーション違反が発生します。

于 2010-11-30T01:29:07.423 に答える
3

strcatあなたが思うようにはしません。最初のパラメーターが指す文字列を変更します。この場合、その文字列は 2 バイトの配列に含まれているため、オーバーランします。

于 2010-11-30T00:50:52.810 に答える
2

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

于 2010-11-30T00:52:33.183 に答える
1

あなたの gets 呼び出しは、いつでも未定義の動作を引き起こすのに十分な文字をすでに追加している可能性があります。

于 2010-11-30T00:50:32.497 に答える
1

whitespaceseparator連結された文字列を含めるのに十分な大きさではないため、未定義の動作を引き起こしています。

使用するgetsことも通常は嫌われます。

于 2010-11-30T00:51:19.003 に答える
1

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

まず、whitespaceseparator2バイトだけ大きいですか?それがあなたが望むものだと確信していますか?そして、あなたはそれに連結pidstringしますか?私はあなたが議論を混乱させたと思います。

ただし、一般strcatに、バッファ サイズに十分注意しないと、デバッグが困難なクラッシュが発生します。より安全な代替手段があります。

于 2010-11-30T00:51:36.973 に答える
1

「文字列の連結」は、C を学ぶときにやめるべきイディオムです。これは、バッファのオーバーフローによる多くのバグにつながるだけではありません。また、非常に非効率的です。snprintfコードでは、フォーマット文字列にスペースを含めることもできます ( の代わりに使用する必要がありますsprintf)。

可能な限り、 を使用して文字列全体を 1 つのステップで組み立てるようにしてくださいsnprintf。これにより、すべてのバッファ長チェックが 1 か所に統合​​され、間違いが非常に難しくなります。snprintf出力のサイズが事前にわからない場合は、割り当てるサイズを調べるために、サイズ引数 0 を指定して呼び出して、結合された文字列の長さを取得することもできます (これよりも 1 バイト多く割り当てる必要があります)。 null ターミネータによって出力が切り捨てられないように長さを調整してください)。

于 2010-11-30T01:37:16.830 に答える