为什么这种产生可能会被破坏......"警告?

时间:2014-08-12 12:29:51

标签: c linux gcc gcc-warning

我试图理解为什么下面的代码生成一个"参数可能被破坏了。"警告。这是一个极小的样本:

#include <unistd.h>

extern char ** environ;

int test_vfork(char **args, char **newEnviron)
{
    pid_t pid = vfork();
    if (pid == 0) {
        execve(args[0], args, (newEnviron != NULL)? newEnviron : environ);
    }

    return 0;
}

这是输出(这是gcc 4.3.3):

$ gcc -O2 -Wclobbered -c test.c -o test.o
test.c: In function ‘test_vfork’:
test.c:5: warning: argument ‘newEnviron’ might be clobbered by ‘longjmp’ or ‘vfork’

另外,如果我用以下内容替换execve行,我发现警告消失了:

    if (newEnviron != NULL)
        execve(commandLine[0], commandLine, newEnviron);
    else
        execve(commandLine[0], commandLine, environ);

不确定为什么gcc比原版更喜欢这个。任何人都能解释一下吗?

1 个答案:

答案 0 :(得分:2)

来自C99&#39; longjmp 说明:

All accessible objects have values, and all other components of the abstract
machine218) have state, as of the time the longjmp function was called, except
that the values of objects of automatic storage duration that are local to the
function containing the invocation of the corresponding setjmp macro that do not
have volatile-qualified type and have been changed between the setjmp invocation
and longjmp call are indeterminate.

如果您将 newEnviron 设为易失性对象,则此段落表示 newEnviron 不会被 longjmp 破坏。 vfork 的规范或实施可能有类似的警告。

<强> - 编辑 -

因为您已启用优化,并且因为 newEnviron 易失性,并且因为在三元条件运算符中使用后未访问它,所以实现可以执行一次优化对于条件运算符,实际上将使用 environ 的值重新分配 newEnviron 。类似的东西:

execve(args[0], args, (newEnviron = newEnviron ? newEnviron : environ));

但我们从 vfork 手册中了解到,在 execve 之前修改大多数对象会导致未定义的行为。

由于没有这样的条件测试,

args 不会受到同样的担忧。

您的 if 语句包含更多序列点,除此之外,可能不会像优化机会那样容易识别。但是,我猜测序列点在优化中发挥了重要作用。

顺便说一句,优化是 newEnviron 的存储被重新用于条件运算符的结果,这意味着既不使用另一个寄存器(如果通常使用寄存器),也不会使用额外的堆栈-space是必需的(对于使用堆栈的系统)。

我敢打赌,如果你能够说服 gcc 你需要在 execve 之后访问 newEnviron 的值行,优化是不可能的,你的警告就会消失。

但当然,使用 volatile 也是一个简单的解决方案。