c-导致无限输出的管道



当我简单地用管道进行ls-l |排序时,程序只会无限地吐出ls-l的结果。有人能看到出了什么问题吗?假设您只需要查看主函数。不过,这将编译。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/wait.h>

#define COMMAND_LINE_LENGTH 256
#define HISTORY_LENGTH 10
#define TOKEN_MAX 50
#define DIRECTORY_LENGTH 5
#define DIRECTORY_PREFIX "/bin/"
struct prog_def
{
    //Binary location
    char *bin;
    //Is this program expecting a pipe?
    int expecting_pipe;
    //Arguments
    char *args[TOKEN_MAX + 1];
    pid_t pid;
} prog_def;
int get_prog_defs(const char* buf, struct prog_def prog_defs[])
{
    char *line = malloc(strlen(buf) + 1);
    int prog_count = 0;
    char* token;
    strcpy(line, buf);
    line[strlen(buf)] = 0;
    while(1)
    {
        int arg_count = 0;
        //The first time through we have to pass the line
        token = strtok(line, " ");
        //Each subsequent call we have to pass NULL
        //http://www.cplusplus.com/reference/cstring/strtok/
        line = NULL;
        //Start building the binary location string
        prog_defs[prog_count].bin = (char*)malloc(strlen(token) + DIRECTORY_LENGTH + 1);
        //Concatenate the directory prefix and command name
        strcat(prog_defs[prog_count].bin, DIRECTORY_PREFIX);
        strcat(prog_defs[prog_count].bin, token);
        //The first argument execvp will expect is the binary location itself
        //Redundant but if I wasn't too lazy to read the doc then I'd know why
        prog_defs[prog_count].args[arg_count++] = prog_defs[prog_count].bin;
        while(1)
        {
            prog_defs[prog_count].expecting_pipe = 0;
            //Check next token for end, pipe, IO redirection, or argument
            token = strtok(NULL, " ");
            //If we've consumed all tokens
            if (token == NULL)
                break;
            //Pipe
            if (strcmp(token, "|") == 0)
            {
                prog_defs[prog_count - 1].expecting_pipe = 1;
                break;
            }
            //Regular argument
            prog_defs[prog_count].args[arg_count++] = token;
        }
        ++prog_count;
        if (token == NULL) break;
    }
    return prog_count;
}

int main(int argc, char** argv)
{
    char command[COMMAND_LINE_LENGTH] = {0};
    //Generic loop counter
    int x = 0;
    while(1)
    {
        printf(">");
        //Get the command
        gets(command);
        struct prog_def prog_defs[TOKEN_MAX];
        int prog_count = get_prog_defs(command, prog_defs);
        //Keep the previous out fd for the in of the subsequent process
        int prev_out_fd = open("/dev/null", O_RDONLY);
        for (x = 0; x < prog_count; ++x)
        {
            //Create a pipe for both processes to share
            int pipefd[2];
            if (x != prog_count -1)
            {
                pipe(pipefd);
            }
            prog_defs[x].pid = fork();
            if(prog_defs[x].pid == 0)
            {
                dup2(prev_out_fd, STDIN_FILENO);
                close(pipefd[1]);
                if(x != prog_count - 1)
                {
                    dup2(pipefd[1], STDOUT_FILENO);
                    close(pipefd[0]);
                    close(pipefd[1]);
                }

                execvp(prog_defs[x].bin, prog_defs[x].args);
            prev_out_fd = pipefd[0];
            close(pipefd[1]);
            }
        close(prev_out_fd);
            prev_out_fd = pipefd[0];
            close(pipefd[1]);
        }
        printf("n");
        for (x = 0; x < prog_count; ++x)
        {
            waitpid(prog_defs[x].pid, NULL, 0);
        }
    }
}

您调用malloc为字符串获取一些内存,该字符串将未初始化,因此包含随机垃圾。然后调用strcat,它将尝试将另一个字符串附加到随机垃圾中,并且几乎可以肯定会耗尽malloc'd空间的末尾,从而导致随机混淆行为和崩溃。

在递增prog_count之前也要使用prog_defs[prog_count - 1],因此第一次通过循环时(当prog_count == 0时),这将在数组开始之前写入,这也会导致随机混淆行为和崩溃。

最新更新