C

时间:2018-07-28 23:53:51

标签: c null pipe strcat

这首先是我的整个代码:

 1. #include <stdio.h>
 2. #include <stdlib.h>
 3. #include <unistd.h>
 4. #include <sys/wait.h>
 5. #include <string.h>
 6. int main(int argc, char *argv[]) {
 7.     int p[2]; // p[0]: file descriptor for read end of pipe
 8.               // p[1]: file descriptor for write end of pipe
 9.     if (pipe(p) < 0) exit(1);
 10.    int rc1 = fork();
 11.    if (rc1 < 0){ fprintf(stderr, "fork error\n"); }
 12.    else if (rc1 == 0){ write(p[1], "1st child output",
 13.                              sizeof("1st child output")); }
 14.    else{
 15.        int rc2 = fork();
 16.        if (rc2 < 0){ fprintf(stderr, "fork error\n"); }
 17.        else if (rc2 == 0){
 18.            printf("2st child output\n");
 19.            char *_1st_child_out;
 20.            read(p[0], _1st_child_out, sizeof("1st child output"));
 21.            strcat(_1st_child_out, ", AFTER PIPE YA FOOL");
 22.            printf("%s\n", _1st_child_out);
 23.        }
 24.    }
 25. }

如果我初始化19:13:

  

字符* _1st_child_out;

带有'\ 0'或NULL, 字符串保持为空,并且22:13:

  

printf(“%s \ n”,_1st_child_out);

什么都不打印,那么strcat()和read()如何工作? 我应该在调用它们之前不插入任何空终止符吗? 那垃圾值呢?

3 个答案:

答案 0 :(得分:0)

您的第19行的指针未指向任何已分配的内存。将其更改为char数组将解决此问题。

char _1st_child_out[100];

此外,为了安全起见,请勿使用strcat。诸如strcpy之类的所有str函数均不检查目标边界。它们都具有n版本。 strcat应该替换为strncat,它将使用第三个参数来指定cat的最大长度,这样就不会发生缓冲区溢出。

答案 1 :(得分:0)

READ(2)不关心'\ 0',也不关心他读取的任何值。 STRCAT(3)将在给定const char *src指针的末尾从'\ 0'读取和写入(操作,而不是函数)。

据我所见,_1st_child_out是一个未初始化的指针。 在READ(2)的第二个位置会有

dest[i] = array_bytes[i];

但是在这里,您的char *_1st_child_out被赋予了一个完全的“随机”值,并且您只会在内存中随机写入某个位置,大多数情况下,这将导致分段错误,并且您的程序将崩溃。 / p>

然后,您需要在这里注意使用sizeof运算符, 您给了他"1st child output",它将在C语言中解释为const char[],并将sizeof("1st child output")替换为值17(16个字符和'\ 0')。 您需要在其中指定类型或变量。

对于数组,例如type array[x]sizeof(array)将与sizeof(type) * x相同。

为了修复程序,请尝试创建静态分配的缓冲区,例如 char _1st_child_out[x];,其中“ x”是缓冲区的大小(以字节为单位)。 或尝试使用MALLOC(3)。 然后修复您的第三个参数READ(2)

在使用STRCAT(3)时,您需要知道,如果给定目标缓冲区的大小不足以容纳", AFTER PIPE YA FOOL",则您的程序很有可能崩溃。

答案 2 :(得分:0)

您的代码中几乎没有错误,这是我的观察结果。

情况1:-在您的代码中,您两次调用fork(),管道写入端p[1]在头{{1}中包含一些数据1st child output } fork()进程,但是您的代码尝试在第二个rc1进程中读取表单p[0]

您应该检查rc2返回值是否成功,或者是否是从错误/未初始化的文件描述符中读取的。这个

read()

由于数据是在 char *_1st_child_out = NULL; /* for process rc2, p[0] contains nothing, so what read() will read from p[0] ?? */ int ret = read(p[0], _1st_child_out, sizeof("1st child output")); if(ret == -1) { perror("read"); /* error handling */ } 进程中而不是在p[1]进程中写入rc1的,但是在这里,当您尝试从rc2读取数据时,就会为您提供

  

读取:错误的地址

案例2:-要克服上述问题,一种方法是

p[0]

这里int main(int argc, char *argv[]) { int p[2]; // p[0]: file descriptor for read end of pipe // p[1]: file descriptor for write end of pipe if (pipe(p) < 0) exit(1); int rc1 = fork(); if (rc1 < 0){ fprintf(stderr, "fork error\n"); } else if (rc1 == 0){ write(p[1], "1st child output",sizeof("1st child output")); } else{ char *_1st_child_out = NULL; /* read() will read from p[0] and store into _1st_child_out but _1st_child_out not holding any valid memory ? So it causes Undefined behavior */ int ret = read(p[0], _1st_child_out, sizeof("1st child output")); if(ret == -1) { perror("read"); /* error handling */ } strcat(_1st_child_out, ", AFTER PIPE YA FOOL"); printf("%s\n", _1st_child_out); } return 0; } 是一个指针,指针应具有有效的内存位置。您可以使用_1st_child_out(即NULL)进行初始化,这是有效的,但不能使用(void*)0进行初始化,因为它只是一个字符。

但是,当您使用\0初始化_1st_child_out并从NULL中读取数据并存储到p[0]中时,它将存储在其中吗?这会导致细分错误,并且也是未定义的行为

因此,最好为_1st_child_out动态分配内存,然后调用_1st_child_out或像这样创建堆栈分配的数组

read()

这是示例工作代码

char _1st_child_out[10];

注意:请使用int main(int argc, char *argv[]) { int p[2]; // p[0]: file descriptor for read end of pipe // p[1]: file descriptor for write end of pipe if (pipe(p) < 0) exit(1); int rc1 = fork(); if (rc1 < 0){ fprintf(stderr, "fork error\n"); } else if (rc1 == 0){ write(p[1], "1st child output",sizeof("1st child output")); } else{ char *_1st_child_out = malloc(BYTE); /* define BYTE value as how much memory needed, and free the dynamically allocated memory once job is done */ int ret = read(p[0], _1st_child_out, sizeof("1st child output")); if(ret == -1) { perror("read"); /* error handling */ } /* make sure _1st_child_out has enough memory space to concatenate */ strcat(_1st_child_out, ", AFTER PIPE YA FOOL"); printf("%s\n", _1st_child_out); } return 0; } 代替strncat(),原因是您可以从strcat() https://linux.die.net/man/3/strcat的手册页中找到

  

strcat()函数将strcat()字符串附加到src字符串中,   在以下位置覆盖终止的空字节(dest)          '\0'的末尾,然后添加一个终止的空字节。字符串不能重叠,dest字符串必须          有足够的空间来存放结果。如果dest不够大,则程序行为是不可预测的缓冲区过度          运行是攻击安全程序的最常用途径

dest