简体   繁体   English

fork / exec:stderr / stdout丢失

[英]fork/exec: stderr/stdout lost

I wrote a programm which starts a new process group and then forks. 我写这将启动一个新的进程组,然后派生一个PROGRAMM。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(int argc, char** argv) {
    if(0 != setpgid(0,0)) {
        fprintf(stderr, "Process group creation failed.");
    }
    pid_t pid = fork();
    if(-1 == pid) {
        // ups, error
        fprintf(stderr, "Fork failed!\n");
        return 1;
    } else if(0==pid) {
        // this is the child process
        char **partial = malloc((argc-1)*sizeof(char*));
        for(int i=1;i<argc;i++) {
            partial[i-1] = argv[i];
        }
        execvp(partial[0], partial);
        exit(127);
    }
    // this is the parent process
    int status;
    waitpid(pid, &status, 0);
    return status;
}

If I call it with 如果我用

./pgroup echo Test

it works as expected. 它按预期工作。

If I call it with 如果我用

./pgroup bash -c "echo Test"

No output is written to my terminal. 没有输出写入我的终端。 Why is that? 这是为什么?

The execve call is causing a segfault: execve调用导致段错误:

==22934== Command: ./testt bash -c echo\ Test
==22934== 
==22935== Syscall param execve(argv) points to unaddressable byte(s)
==22935==    at 0x4EF9537: execve (in /usr/lib64/libc-2.20.so)
==22935==    by 0x4EF9D35: execvpe (in /usr/lib64/libc-2.20.so)
==22935==    by 0x400822: main (testt.c:23)
==22935==  Address 0x51f2058 is 0 bytes after a block of size 24 alloc'd
==22935==    at 0x4C29BCF: malloc (in /usr/lib64/valgrind /vgpreload_memcheck-amd64-linux.so)
==22935==    by 0x4007C5: main (testt.c:18)
==22935== 

In particular, don't mess with argv[0] (you don't here, but just sayin). 特别是,不要弄乱argv [0](您不在这里,只说而已)。 And - this is the key here - you've got to strcpy() the other args into heap space, not just pass existing pointers. 而且-这是关键-您必须将其他args strcpy()放入堆空间,而不仅仅是传递现有的指针。 You didn't allocate that argv, so don't expect it to "stick around" when the startup routine runs again, etc... Lastly, you need to copy a NULL to the and of the argument list. 您没有分配该argv,因此不要期望它在启动例程再次运行时“缠住”等等。最后,您需要将NULL复制到参数列表的和。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

Do not mix headers like that. 不要这样混合标题。 sys/ headers go first. sys /标头放在首位。

int main(int argc, char** argv) {
    if(0 != setpgid(0,0)) {
        fprintf(stderr, "Process group creation failed.");
    }

Yoda-style comparisons look terrible and have no merit. 尤达式的比较看起来很糟糕,没有优点。

    pid_t pid = fork();
    if(-1 == pid) {
        // ups, error
        fprintf(stderr, "Fork failed!\n");
        return 1;
    } else if(0==pid) {
        // this is the child process
        char **partial = malloc((argc-1)*sizeof(char*));
        for(int i=1;i<argc;i++) {
            partial[i-1] = argv[i];
        }

What's the point of this exercise? 这个练习的目的是什么? How about argv++ and then you can use it directly in execvp. argv ++怎么样,然后您可以直接在execvp中使用它。 Your loop is atrocious and unnecessary. 你的循环是残暴的,不必要的。 You malloc argc - 1, but loop condition is i < argc which is incosistent, which is made up for by another weirdness of i not starting from 0. Error inducing style. 您malloc argc-1,但循环条件是i <argc,这是不可思议的,这是由i的另一个怪异(不是从0开始)弥补的。错误引发样式。

Also you did not validate any arguments. 另外,您没有验证任何参数。

        execvp(partial[0], partial);

If you checked the error you would see that fails. 如果检查了错误,您将看到失败。 The simplest "first contact" tool is strace, it would have told you exactly what's up, see: 最简单的“首次联系”工具是strace,它将告诉您确切的情况,请参阅:

[pid 15735] execve("/usr/bin/bash", ["bash", "-c", "echo test", 0x20fe1], [/* 58 vars */]) = -1 EFAULT (Bad address) [pid 15735] execve(“ / usr / bin / bash”,[“ bash”,“ -c”,“ echo test”,0x20fe1],[/ * 58 vars * /])= -1 EFAULT(错误地址)

From this it is obvious that arg array is not properly terminated and the kernel tried to copy in some garbage. 由此可见,arg数组未正确终止,内核尝试在某些垃圾中进行复制。

So, your 'echo test' example worked by pure accident as it happened to have a zero in there. 因此,您的“回声测试”示例纯属偶然,因为它恰好在其中为零。

If you had debugging enabled in your malloc it would have failed for that case as well. 如果您在malloc中启用了调试,则在这种情况下也会失败。

        exit(127);

That's not how you exit in a child which did not execve. 那不是你如何退出一个没有被执行的孩子。 See _Exit. 参见_Exit。

    }
    // this is the parent process
    int status;
    waitpid(pid, &status, 0);
    return status;

This value is not suitable for retutning. 此值不适合撤消。 See relevant macros in waitpid manpage. 请参见waitpid联机帮助页中的相关宏。 The shell supports values from 0 to 255. This returns 32512 which is divisible by 256 and thus ends up being 0. 壳支撑的值从0到255这样的回报32512它是由256整除,因此最终被0。

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM