execve() 有一个奇怪的行为取决于一个未使用的变量的状态

问题描述

我最近刚刚在探索 execve() 系统函数。这段代码可能没有多大意义,但这不是这个问题的主要焦点。 (自从使用 this 线程以来,我设法使其正常工作。

我遇到了一个非常奇怪的行为,想要一个解释或确认这样的事情不应该发生。

“被窃听”的代码是这样的:

#include <unistd.h>

int main(int argc,char **argv,char **env)
{
    if (argc != 2)
        return (ERROR_CODE);
    char *test[] = { argv[1] };
    char *a[] = { NULL };

    execve(argv[1],test,env);
    return (SUCCESS_CODE);
}

使用参数编译和执行它会正确执行该函数,在我的例子中:

$> gcc main.c
$> ./a.out "/bin/ls"

这会像 ls 函数一样工作。 现在删除/评论这一行:

char *a[] = { NULL };

这个变量显然没有使用,完全没用。 再次执行相同的步骤,出于某种原因,它不输出任何内容,这个随机变量对我来说破坏了代码。 (我使用 Gnome 3.36.8 和 gcc 9.3.0 运行 Ubuntu 20.04)。

如果您需要有关我的操作系统或任何其他内容的更多信息,请随时询问。

PS:我想我理解代码试图解决这个问题的方式,但这对我来说没有意义。

$> man execve

main(int argc,char *argv[])
char *newargv[] = { NULL,"hello","world",NULL };
...
execve(argv[1],newargv,newenviron);

手动示例以空终止“newargv”,我的想法是不知何故,编译器决定将我的变量“test”和“a”融合在一起,以空终止“test”?

解决方法

是的,您意外看到了“融合”,因为您没有正确地用 argv 终止 NULL 并且内存布局恰好对您有利.如果你不那么幸运,你会在那里得到垃圾,或者段错误。

引用手册页 (Linux,Darwin),强调我的,

参数 argv 是一个指向空终止数组的指针,该数组由指向空终止字符串的字符指针组成。

#include <unistd.h>

int main(int argc,char **argv,char **env)
{
    if (argc != 2)
        return (ERROR_CODE);
    char *test[] = { argv[1],NULL };

    execve(argv[1],test,env);
    return (SUCCESS_CODE);
}

应该是正确的调用。