javac数据流分析的诡异误报

Posted

技术标签:

【中文标题】javac数据流分析的诡异误报【英文标题】:Weird false-positive of javac data flow analysis 【发布时间】:2012-02-25 03:25:36 【问题描述】:

我有以下形式的代码:

class Test 
  private final A t;

  public Test() 

    for ( ... : ... ) 
      final A u = null;
    

    t = new A();
  

  private class A 

编译器说:

variable t might already have been assigned

有趣的是,如果我对循环执行以下任何更改,它就会成功!

将循环内容更改为A u = null 删除循环(但保留final A u = null;) 将 foreach 样式的循环替换为经典的计数循环

这是怎么回事?

注意:我无法获得导致错误的最小示例,因此“环境”(大约 1400 位置)可能有问题。不过,我看不出有什么会干扰t 的初始化,因为t 没有写入其他任何地方。

有趣的事实:如果我删除它,IntelliJ IDEA 会说“变量 'u' 可以有 'final' 修饰符...”。

我使用 javac 1.6.0_26。

更新:你去吧,这个例子是如此如此最小:

import java.util.List;

class A 
  private final boolean a;

  public A() 
    for ( final Object o : new Object[]  ) 
      final Object sh = null;
    

    a = true;
  

  class B 
    private final Object b1;
    private final Object b2;

    B() 
      b1 = null;
      b2 = null;
    
  

javac 1.6.0_26 上编译失败,但在javac 1.7.0_02 上编译。所以我想我遇到了一些邪恶的角落案例......什么?

请注意,您可以执行任何操作

删除任何一个成员 在A() 的循环中删除final 用普通的for 循环替换循环,例如for ( int i=0; i<100; i++ ) ...

它会编译。

【问题讨论】:

您可能有自定义编译器设置,您使用的是哪个 IDE? 我跑mvn install;我们的项目没有定义编译器参数(afaik)。 对我来说似乎是一个 IntelliJ 问题。 Eclipse 对我来说没有出现这个问题。当然,如果循环没有引用t,那么它不应该在以后影响它。 CLI maven 显示错误。我同意它不应该,但确实如此。 【参考方案1】:

如果你有很多代码,我会试试这个。

private final A t;

public Test() 
    final int t = 1;

   for ( ... ) 
      final A u = null;
   

   this.t = new A();

这将导致任何“可能”初始化 t 的代码失败(并显示在编译器中。

【讨论】:

正如我在问题中所说,Test#t 没有其他写信。我通过用法搜索、字符串搜索和 - 只是为了逗你开心 - 按照你的建议通过引发编译器错误来确认这一点。 谢谢,您的回复很有趣。 ;)【参考方案2】:

如果你的构造函数碰巧调用了另一个本身没有设置t的构造函数,编译器将无法理解。

见here。

【讨论】:

感谢您的回答。我其实也想过这个,但是不,没有这样的电话。其实我只定义了这一个构造函数。我真正的课程是***课程,不扩展任何其他课程(但Object),因此在这方面不应该有任何干扰。它实现了一个接口,但这不应该受到伤害。 @Raphael 我猜你最好提供一个SSCCE,但它当然不应该编译......它在 IntelliJ 中编译得很好。 如果我知道基本部分,我就会知道问题所在,你不觉得吗? ;) 我不知道外部的东西会如何影响这一点,所以我不知道从哪里开始添加/删除东西。不过,我正在尝试。 我花了一段时间,但我现在有一个小例子。见上文。【参考方案3】:

由于该问题在 Java 7 中已修复,因此可能是 Java 6 编译器中的错误。

【讨论】:

【参考方案4】:

据我了解,将对象存储在 final var 中并不会使您的对象不可变,而是使其引用。这解释了为什么当您删除 final 关键字时它会起作用,并且根据删除 for 循环,我认为您正在访问对象引用而不是实例。

【讨论】:

u 在其初始化后永远不会被访问或写入(以仍然无法编译的真实代码的简化形式)。

以上是关于javac数据流分析的诡异误报的主要内容,如果未能解决你的问题,请参考以下文章

案例分析:你造吗?有个ORA-60死锁的解决方案

Javac

Javac

Javac

代码静态分析工具的误报原因分析

代码静态分析工具的误报原因分析