【问题标题】:execv() system call creating stacking smashing errorexecv() 系统调用创建堆叠粉碎错误
【发布时间】:2018-03-18 02:32:11
【问题描述】:

每当我在我的代码中使用 execv() 时,它都可以正常工作并且没有错误,但仍然会导致堆栈粉碎导致程序在运行时崩溃。我在这里做错什么了吗? 这是带有 execv() 的函数:

void execute(char *args[], char *cmd[])
{
    pid_t pid;
    int status;
    char bin[10] = "/bin/";
    pid = fork();

    // child process
    if(pid == 0)
    {
         strcat(bin, cmd[0]);

    execv(bin, args);   
    } else{
   perror("error");
    while(wait(&status) != pid);
    }
}

这是我从中获取 args 和 cmd 的地方。会不会是我在这里做的事情造成的?

void parseString(char *command)
{
    char **args = malloc(sizeof(char*) * 16);
    int i = 0;
    int j = 0;
    char *cmd[1];

    // split each command by semicolons if necessary, then send each sub        command to parseString()
    if(strchr(command, ';')) {
        char *semi_token = strtok(command, ";");
        while(semi_token != NULL){
            args[i] = semi_token;
            semi_token = strtok(NULL, " ");
            parseString(args[i]);
            i++;
        }
    } else {
        // if no semi colons, split the commandby spaces and call execute() using the args and cmd
        char *token = strtok(command, " ");
        while(token != NULL)
        {
            args[i] = token;
            args[++i] = NULL;
            while(j == 0 && token != NULL) {
                    cmd[0] = token;
                    cmd[1] = NULL;
                    j++;
                }
            token = strtok(NULL, " ");
            }
            execute(args, cmd);
        }

        j = 0;
        i = 0;
        free(args);
    }

函数调用发生在这里。命令是用户从标准输入输入的。只需要位于/bin/ 中的基本命令。类似 ls -l 或 cat 文件。

while(1){
        command = getCommand();
        parseString(command);
}

【问题讨论】:

  • 在你的execute函数中,cmd[0]的内容是什么?它会超过四个字符吗?因为这就是bin 的全部内容。
  • 而且你只限制了 15 个参数,你有超过 15 个参数吗?
  • 总是在父级中调用perror("error"); 是错误的。可以说,您应该检测pid == -1(或pid < 0)然后报告错误是合适的。您没有展示如何调用代码,也没有解释您提供的输入内容。您通常没有创建 MCVE (minimal reproducible example),因此很难看到您在做什么。但是你在你的execute() 函数中过于简洁——char bin[100] = "/bin/"; 可能会更好,但并不是每个命令都在/bin 中(有/usr/local/bin,有时/usr/bin/bin 是分开的)。
  • 顺便说一句,不要忘记execv 也可能失败。而在你当前的计划中,发生的事情可能比你想象的要多,并导致坏事。
  • 或者在execv后面加一个exit(1),这样子进程在execv失败后退出。

标签: c stack-smash


【解决方案1】:

您有两个严重错误:一个会导致数组越界写入,另一个可能会导致该错误。

第一个,某些越界写入,在parseString 函数中。首先你有cmd变量的声明:

char *cmd[1];

这将 cmd 定义为 one 元素的数组。那你就做

cmd[0] = token;
cmd[1] = NULL;

写入单元素数组的 两个 元素。越界写入会导致undefined behavior

第二个错误在execute 函数中,也是我在第一条评论中谈到的那个。你有

char bin[10] = "/bin/";

这将bin 定义为一个由十个字符组成的数组,然后你填满其中的六个(不要忘记字符串终止符)。在你做的子进程中

strcat(bin, cmd[0]);

cmd[0] 中的字符串附加到bin 中的字符串。这里的问题是bin 只有十个字符的空间,其中六个已被使用(如上所述)。这意味着只剩下四个字符的空间。如果命令比这更长,您也会超出范围并再次出现未定义的行为

第一个错误的解决方法很简单,将cmd 设为一个包含两个元素的数组。第二个错误的解决方案是使bin 更大,并且不要连接超过数组可以容纳的数量;或者动态分配数组(不要忘记终止符的空间)。

您的代码还有很多其他潜在问题,例如 args 的 16 个指针的限制。并且您并没有真正解析 parseString 函数中的参数,每个参数都被视为一个单独的命令。并且内存泄漏的情况下有分号分隔的“命令”。或者您不在任何需要的地方检查或处理错误。并且你使用errno,即使没有错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-06-08
    • 1970-01-01
    • 1970-01-01
    • 2015-01-12
    • 1970-01-01
    • 1970-01-01
    • 2011-07-20
    相关资源
    最近更新 更多