strcat分段故障

时间:2010-11-30 00:48:07

标签: c 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;
}

7 个答案:

答案 0 :(得分:4)

我尝试了您的代码,并在第二个strcat()上看到了段错误。我发现command[250]在我的系统堆栈上的whitespaceseparator[2]后立即分配:

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

e.g。 (这里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的字符串。副本的第一个字符将覆盖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" ...直到它从进程地址空间的末尾掉落,此时会出现段错误。

答案 1 :(得分:3)

strcat没有按你的想法行事。它修改了第一个参数指向的字符串。在这种情况下,该字符串包含在一个2字节的数组中,因此会溢出。

答案 2 :(得分:2)

为避免缓冲区溢出错误,但使用strcat,您应该使用strncat函数。

答案 3 :(得分:1)

您的获取调用可能已经添加了足够的字符,以便随时导致未定义的行为。

答案 4 :(得分:1)

whitespaceseparator不足以包含连接字符串,因此导致未定义的行为。

使用gets通常也不赞成。

答案 5 :(得分:1)

strcat通常是不安全的,因为它可以很高兴地溢出缓冲区,就像你的情况一样。

首先,whitespaceseparator只有两个大字节?你确定那是你想要的吗?你连接pidstring到它?我认为你的论点混乱了。

一般情况下,如果您对缓冲区大小不太仔细,strcat将导致难以调试的崩溃。有更安全的替代品。

答案 6 :(得分:1)

“字符串连接”是学习C时应该删除的一个习惯用法。它不仅会导致许多带有溢出缓冲区的错误;它也超级低效。在您的代码中,您可以在snprintf格式字符串中包含空格(您应该使用它来代替sprintf)。

尽可能尝试使用snprintf在一个步骤中完全组合字符串。这将所有缓冲区长度检查合并到一个地方,这使得它很难出错。您还可以使用0大小参数调用snprintf以获取组合字符串的长度,以便找出要分配的大小,如果输出的大小未提前知道(您应该分配)比这个长度多一个字节,以便空终止符不会截断你的输出。)