strcat 分段错误

发布于 2024-10-05 02:06:28 字数 1309 浏览 4 评论 0原文

这里第二次调用 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;
}

The second call to strcat here is generating a segmentation fault, why?

#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;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

寂寞美少年 2024-10-12 02:06:29

“字符串连接”是学习 C 语言时应该放弃的习惯用法。它不仅会导致大量缓冲区溢出的错误,而且还会导致错误。这也是超级低效的。在您的代码中,您可以在 snprintf 格式字符串中包含空格(您应该使用它来代替 sprintf)。

只要有可能,请尝试使用 snprintf 在一个步骤中完全组装一个字符串。这将所有缓冲区长度检查合并到一个地方,并且很难出错。如果事先不知道输出的大小(您应该比该长度多分配一个字节,以便空终止符不会截断您的输出)。

"String concatenation" is an idiom you should drop when learning C. Not only does it lead to a lot of bugs with overflowing buffers; it's also super inefficient. In your code, you could just have included the space in the snprintf format string (you should be using it in place of sprintf).

Whenever possible, try to assemble a string entirely in one step using snprintf. This consolidates all of the buffer length checking into one place and makes it really hard to get wrong. You can also call snprintf with a 0 size argument to get the length that the combined string would be, in order to find out what size to allocate, if the size of the output is not known in advance (you should allocate one more byte than this length so that the null terminator does not truncate your output).

彩虹直至黑白 2024-10-12 02:06:28

我尝试了您的代码,并且还看到第二个 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 |'.'|'.'| ...
+---+---+---+---+---+---+---+---+

第二个 < code>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"...直到它脱离进程地址空间的末尾,此时您会遇到段错误。

I tried your code, and also see the segfault on the second strcat(). I found that command[250] is allocated immediately after whitespaceseparator[2] on the stack on my system:

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

e.g. (here command begins "foo..."), things are layed out like this:

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

I can't guarantee that the same happens on your system (layout of locals on the stack may vary even between different versions of the same compiler), but it seems likely. On mine, here is exactly what happens:

As others have said, strcat() appends the second string to the first (and the result will be equal to the first argument). So, the first strcat() overflows whitespaceseparator[] (and returns whitespaceseparator as whitespace_and_pid):

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

The second strcat() tries to append whitespace_and_pid (== whitespaceseparator) to the string at command. The first character of the copy will overwrite the terminating 0 of the string at command:

  |    ===copy===>    |
  v                   v
+---+---+---+---+---+---+---+---+
|' '|'1'|'2'|'3'|'4'|' '|'.'|'.'| ...
+---+---+---+---+---+---+---+---+

The copy continues...

      |    ===copy===>    |
      v                   v
+---+---+---+---+---+---+---+---+
|' '|'1'|'2'|'3'|'4'|' '|'1'|'.'| ...
+---+---+---+---+---+---+---+---+

          |    ===copy===>    |
          v                   v
+---+---+---+---+---+---+---+---+
|' '|'1'|'2'|'3'|'4'|' '|'1'|'2'| ...
+---+---+---+---+---+---+---+---+

and will carry on copying " 1234 1234 1234"... until it falls off the end of the process address space, at which point you get a segfault.

上课铃就是安魂曲 2024-10-12 02:06:28

strcat 不会按照你的想法做。它修改第一个参数指向的字符串。在本例中,该字符串包含在 2 字节数组中,因此会溢出。

strcat doesn't do what you think. It modifies the string pointed to by its first parameter. In this case, that string is contained in a 2-byte array, which is therefore overrun.

强辩 2024-10-12 02:06:28

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

To avoid buffer overflow errors, but use strcat you should to use strncat function.

彻夜缠绵 2024-10-12 02:06:28

您的 get 调用可能已经添加了足够的字符,从而在任何时候都会导致未定义的行为。

Your gets call could have added sufficient characters already to cause undefined behavior at about anytime.

绅刃 2024-10-12 02:06:28

whitespaceseparator 不够大,无法包含连接的字符串,因此会导致未定义的行为。

使用 gets 通常也不受欢迎。

whitespaceseparator isn't big enough to contain the concatenated string, so you're causing undefined behaviour.

Using gets is normally frowned upon, too.

花桑 2024-10-12 02:06:28

strcat 通常是不安全的,因为它可以愉快地溢出缓冲区,就像您的情况一样。

首先,whitespaceseparator只有两个字节大?你确定这就是你想要的吗?然后将 pidstring 连接到它?我认为你把论点搞混了。

但一般来说,如果您对缓冲区大小不太小心,strcat 将导致难以调试的崩溃。有更安全的替代方案。

strcat is generally unsafe because it can happily overrun buffers, like it does in your case.

First of all, whitespaceseparator is only two bytes large? Are you sure that's what you want? And you concatenate pidstring to it? I think you got the arguments mixed up.

In general though, strcat will cause hard-to-debug crashes if you're not very careful with your buffer sizes. There are safer alternatives.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文