“未初始化使用”警告在g ++编译器 [英] “Uninitialized use” warning in the g++ compiler

查看:927
本文介绍了“未初始化使用”警告在g ++编译器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用g ++的警告级别 -Wall -Wextra 并将警告视为错误( -Werror ) 。



现在我有时会收到错误可能会在此函数中未初始化。



由有时我的意思是我有两个独立的编译单元,都包括相同的头文件。一个编译单元编译没有错误,另一个编译单元编译错误。



头文件中的相关代码如下。由于函数很长,我只能复制下面的相关位。



确切的错误是:



< blockquote>

'cmpres'可能在此函数中未初始化


下面的 * 的错误。

  b $ b int cmpres; // * 
while(b <= c和(cmpres = cmp(b,pivot))<= 0){
if(cmpres == 0)
:: std: :iter_swap(a ++,b);
++ b;
}
while(c> = b and(cmpres = cmp(c,pivot))> = 0){
if(cmpres == 0)
:: std :: iter_swap(d--,c);
--c;
}
if(b> c)break;
:: std :: iter_swap(b ++,c--);
}

cmp 函数接受两个指针 x y ,并返回-1,0或+1,如果 * x <* y * x == * y * x> * y

这段代码是一个更大的函数的一部分,但变量 cmpres 中使用。因此,我不明白为什么会产生这个警告。此外,编译器显然理解, cmpres 将永远不会被读取未初始化(或至少,它并不总是警告,见上文)。



现在我有两个问题:


  1. 不一致的行为?这是由试探法产生的警告吗? (这是合理的,因为发出这个警告需要一个控制流分析,在一般情况下是非常困难的,不能总是执行。)


  2. 警告? 是我的代码不安全吗?我来欣赏这个特别的警告,因为它已经救了我从很难在其他情况下检测错误 - 所以这个是一个有效的警告,至少有时。



解决方案

一个用于诊断未初始化变量假阴性或阳性(作为子程序)必须包含解决暂停问题的算法。这意味着没有这样的算法



我不知道GCC的未初始化变量分析是如何工作的,但我知道它对于早期的优化传递对代码已经做了很敏感。所以我并不感到惊讶,你有时只得到假阳性。它确实区分了不能确定的情况 -

  int foo(){int a; return a; } 

会在此函式中产生「警告:」未初始化

编辑:我发现一个最近版本的GCC(4.3及更高版本)失败的情况

em>诊断未初始化的变量:

  int foo(int x)
{
int a;
return x? a:0;
}

早期优化注意到如果 x 非零,函数的行为是未定义的,所以他们假设 x 必须为零 code> return 0; 这发生在生成使用的未初始化警告的pass之前,所以没有诊断。有关详细信息,请参阅 GCC错误18501



我把它部分地表明,生产级编译器可以得到未初始化变量诊断错误的两种方式,部分是因为它是一个很好的例子,未定义的行为可以在执行时间传播反向。测试 x 没有任何未定义,但因为依赖于 x 的代码控制具有未定义的行为,假设控制依赖从未满足并丢弃测试。


I’m using g++ with warning level -Wall -Wextra and treating warnings as errors (-Werror).

Now I’m sometimes getting an error "variable may be used uninitialized in this function".

By "sometimes" I mean that I have two independent compilation units that both include the same header file. One compilation unit compiles without error, the other gives the above error.

The relevant piece of code in the header files is as follows. Since the function is pretty long, I’ve only reproduced the relevant bit below.

The exact error is:

'cmpres' may be used uninitialized in this function

And I’ve marked the line with the error by * below.

for (; ;) {
    int cmpres; // *
    while (b <= c and (cmpres = cmp(b, pivot)) <= 0) {
        if (cmpres == 0)
            ::std::iter_swap(a++, b);
        ++b;
    }
    while (c >= b and (cmpres = cmp(c, pivot)) >= 0) {
        if (cmpres == 0)
            ::std::iter_swap(d--, c);
        --c;
    }
    if (b > c) break;
    ::std::iter_swap(b++, c--);
}

(cmp is a functor that takes two pointers x and y and returns –1, 0 or +1 if *x < *y, *x == *y or *x > *y respectively. The other variables are pointers into the same array.)

This piece of code is part of a larger function but the variable cmpres is used nowhere else. Hence I fail to understand why this warning is generated. Furthermore, the compiler obviously understands that cmpres will never be read uninitialized (or at least, it doesn’t always warn, see above).

Now I have two questions:

  1. Why the inconsistent behaviour? Is this warning generated by a heuristic? (This is plausible since emitting this warning requires a control flow analysis which is NP hard in the general case and cannot always be performed.)

  2. Why the warning? Is my code unsafe? I have come to appreciate this particular warning because it has saved me from very hard to detect bugs in other cases – so this is a valid warning, at least sometimes. Is it valid here?

解决方案

An algorithm that diagnoses uninitialized variables with no false negatives or positives must (as a subroutine) include an algorithm that solves the Halting Problem. Which means there is no such algorithm. It is impossible for a computer to get this right 100% of the time.

I don't know how GCC's uninitialized variable analysis works exactly, but I do know it's very sensitive to what early optimization passes have done to the code. So I'm not at all surprised you get false positives only sometimes. It does distinguish cases where it's certain from cases where it can't be certain --

int foo() { int a; return a; }

produces "warning: ‘a’ is used uninitialized in this function" (emphasis mine).

EDIT: I found a case where recent versions of GCC (4.3 and later) fail to diagnose an uninitialized variable:

int foo(int x)
{
    int a;
    return x ? a : 0;
}

Early optimizations notice that if x is nonzero, the function's behavior is undefined, so they assume x must be zero and replace the entire body of the function with "return 0;" This happens well before the pass that generates the used-uninitialized warnings, so there's no diagnostic. See GCC bug 18501 for gory details.

I bring this up partially to demonstrate that production-grade compilers can get uninitialized-variable diagnostics wrong both ways, and partially because it's a nice example of the point that undefined behavior can propagate backward in execution time. There's nothing undefined about testing x, but because code control-dependent on x has undefined behavior, a compiler is allowed to assume that the control dependency is never satisfied and discard the test.

这篇关于“未初始化使用”警告在g ++编译器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆