这首先是我的整个代码:
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()如何工作? 我应该在调用它们之前不插入任何空终止符吗? 那垃圾值呢?
答案 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