每当我在我的代码中使用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);
}
函数调用发生在这里。命令是从用户的stdin输入的。只需要位于/ bin /中的基本命令。类似于ls -l或cat文件。
while(1){
command = getCommand();
parseString(command);
}
答案 0 :(得分:4)
你有两个严重的错误:一个会导致数组的越界写入,另一个可能会导致错误。
第一个,特定的越界写作,在parseString
函数中。首先,您要声明cmd
变量:
char *cmd[1];
这将cmd
定义为 一个 元素的数组。然后你做
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
。