【问题标题】:Why is this generating a "might be clobbered..." warning?为什么这会产生“可能被破坏......”警告?
【发布时间】:2014-08-12 12:29:50
【问题描述】:

我试图理解为什么以下代码会生成“参数可能被破坏..”警告。这是一个最小的示例:

#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 比原来更喜欢这个。有人能解释一下吗?

【问题讨论】:

  • Clang 3.4(在 OS X 上)可以毫无怨言地编译它,即使使用 -Wall -Wextra。你可以试试(很多)更新的 GCC。
  • @GradyPlayer:我已经检查过了,但不知道这如何适用于这种情况。 newEnviron 参数未通过代码进行修改。
  • 我不认为需要修改它才能得到警告,而且我不知道没有三元的版本与编译器是否可以,我怀疑这是一个错误......但是您是否尝试使用returns_twice 来装饰函数?
  • 代码分析真的很难。感谢 GCC 试图警告你它不确定你的代码是否安全,尽管我非常希望该代码没有真正的危险。

标签: c linux gcc gcc-warning


【解决方案1】:

来自 C99 的 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 设为 volatile 对象,则此段落表明 newEnviron 不会被 longjmp 破坏. vfork 的规范或实现可能有类似的警告。

--编辑--

因为您启用了优化并且因为 newEnviron 是非volatile 并且因为它在三元条件运算符中使用后不会被访问,所以实现可以执行一种优化对于您的条件运算符,实际上是用 environ 的值重新分配 newEnviron。比如:

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

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

args 不会受到同样的担忧,因为没有这样的条件测试。

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

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

我敢打赌,如果您能够说服 gcc 您需要在 execve 行之后访问 newEnviron 的值,无法进行优化,您的警告将消失。

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

【讨论】:

  • 这并没有提供问题的答案。要批评或要求作者澄清,请在其帖子下方发表评论。
  • Davidmh:你去吧。我来不及避免你投反对票。 “任何人都可以阐明”似乎是一个足够模糊的问题,可以用“让它变得不稳定”来回答。意见不一。
  • 如果您认为问题不清楚,请将其标记为此类。现在的答案现在好多了。顺便说一句,否决票不是来自我,但在这里你有我的 +1 :)
  • 我看不出这个问题有多模糊。我在问为什么 gcc 会为 newEnviron 发出这个警告(虽然它没有说任何关于例如 args 的内容),以及为什么第二个版本没有警告。
  • Davidmh:哦,好的。谢谢! :) Grodriguez:我不清楚你的问题(2)你想要什么级别的细节......对于最详细的答案,我们可以深入研究 GCC 的源代码来找到它。对于一个简单的答案,一些见解将是“为了避免警告,请尝试使其 volatile”。我用更详细的猜测编辑了我的答案。希望对您有所帮助!
猜你喜欢
  • 2011-12-05
  • 2011-01-16
  • 2016-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-08
  • 1970-01-01
相关资源
最近更新 更多