malloc on(char **)

时间:2012-12-15 07:13:13

标签: c malloc exec posix fork

好吧,我正在尝试使用C语言为linux编写一个shell。使用函数fork()和execl(),我可以执行每个命令,但现在我一直试图读取参数:

char * command;
char ** c_args = NULL;

bytes_read = getline (&command, &nbytes, stdin);

command = strtok(command, "\n ");
int arg = 0;
c_arg = strtok(NULL, "\n ");
while( c_arg != NULL ) {
    if( c_args == NULL ) {
        c_args = (char**) malloc(sizeof(char*));
    }
    else {
        c_args = (char**) realloc( c_args, sizeof(char*) * (arg + 1) );
    }
    c_args[arg] = (char*) malloc( sizeof(char)*1024 );
    strcpy( c_args[arg], c_arg );
    c_arg = strtok(NULL, "\n ");
    arg++;
}
...
pid_t pid = fork()
...
...
execl( <path>, command, c_args, NULL)
...
...

这样我在尝试传递参数时会从命令中获得错误,例如:

ls -l

给我:

ls: cannot access p��: No such file or directory

我知道问题是c_args分配。怎么了?

干杯。

2 个答案:

答案 0 :(得分:2)

您不能将execl()用于变量参数列表;您需要使用execv()或其中一个变体(execve()execvp()等)。当您知道编译时将出现的所有参数时,您只能使用execl()。在大多数情况下,一般shell都不会知道。例外情况是,当您执行以下操作时:

execl("/bin/sh", "/bin/sh", "-c", command_line, (char *)0);

在这里,您调用shell来运行单个字符串作为命令行(没有其他参数)。但是,当您处理人们在完整shell中键入键盘的内容时,您将无法知道他们在编译时键入了多少个参数。

最简单的,你应该使用:

execvp(c_args[0], c_args);

第0个参数,即命令名称,应该是您传递给execvp()的参数。如果这是一个简单的文件名(无/),那么它将在$PATH环境变量的目录中查找命令。如果命令名称包含斜杠,则它将查找指定的(相对或绝对)文件名,如果存在则执行该文件名,如果不存在则执行。其他参数都应该在以空值终止的列表c_args中。

现在,可能还有其他内存分配问题;我没有仔细检查代码。但是,您可以通过参数列表的诊断打印来检查它们:

char **pargs = c_args;
while (*pargs != 0)
    puts(*pargs++);

将每个参数打印在一个单独的行上。请注意,它在遇到空指针之前不会停止;至关重要的是,null null终止指向参数字符串的指针列表。

你的代码:

c_args[arg] = (char*) malloc( sizeof(char)*1024 );
strcpy( c_args[arg], c_arg );
在通常情况下,

看起来有点过分,而在极端情况下,内存分配不足。当你复制字符串时,分配足够的长度。我看到你正在使用strtok()来破坏字符串 - 它会为shell的早期版本做,但是当你开始处理像ls -l>$tmp这样的命令行时,你会发现{{}在你阅读它之前践踏你的分隔符的倾向成为一个主要的责任。但是,当您使用它时,您可能不必复制那样的参数;你可以设置strtok()。当你需要复制时,你应该使用c_args[arg++] = result_from_strtok;;例如,它不会忘记为尾随strdup()分配足够的空间,既不会过度分配也不会分配不足。

答案 1 :(得分:1)

乔纳森有一个很好的答案,我只是想补充一些东西。

可以使用popensystem直接由shell执行。它们通常不受欢迎,因为它们可以很容易地注入,但如果你正在写一个开壳,我看不出使用它们的危害。

如果您要使用有限的shell(接受类似sh语法),请查看wordexp。它做了很多,但根据我的经验,它确实做得太多了,特别是如果你正在尝试编写一个中等安全的解释器(它确实像波形扩展和变量替换那样愚蠢的事情)。