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

execve() has a weird behavior depending on the state of an unused variable

我最近一直在研究 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 函数一样工作。 现在 remove/comment 这一行:

char *a[] = { NULL };

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

如果您需要有关我的 OS 或任何其他信息,请随时询问。

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

$> man execve

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

手动示例以 null 终止“newargv”,我的想法是编译器以某种方式在某处决定将我的变量“test”和“a”融合在一起,以以 null 终止“test”?

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

引用联机帮助页 (Linux, Darwin),强调我的,

The argument argv is a pointer to a null-terminated array of character pointers to null-terminated character strings.

#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);
}

将是正确的调用。