Java: int数组以非零元素初始化

130
根据JLS的规定,一个int数组在初始化后应该被零填充。然而,我面临的情况是并非如此。这种行为首次出现在JDK 7u4中,并且在所有后续的更新中也存在(我使用64位实现)。以下代码会抛出异常:
public static void main(String[] args) {
        int[] a;
        int n = 0;
        for (int i = 0; i < 100000000; ++i) {
            a = new int[10];
            for (int f : a)
                if (f != 0)
                  throw new RuntimeException("Array just after allocation: "+ Arrays.toString(a));
            Arrays.fill(a, 0);
            for (int j = 0; j < a.length; ++j)
                a[j] = (n - j)*i;
            for (int f : a)
                n += f;
        }
        System.out.println(n);
    }

在JVM对代码块进行编译后,异常会发生,并且不会在使用-Xint标志时出现。此外,Arrays.fill(...)语句(以及代码中的其他语句)是必需的,如果没有它,异常就不会发生。很明显,这个可能的错误与某些JVM优化有关。对于这种行为的原因有什么想法吗?

更新:
我在HotSpot 64位服务器VM上,Java版本从1.7.0_04到1.7.0_10,在Gentoo Linux、Debian Linux(两者都是3.0版本的内核)和MacOS Lion上看到了这种行为。这个错误可以通过上面的代码始终重现。我没有在32位JDK或Windows上测试这个问题。我已经向Oracle发送了一个错误报告(错误ID 7196857),它将在几天内出现在公共的Oracle错误数据库中。

更新:
Oracle在他们的公共错误数据库中发布了这个错误:https://bugs.java.com/bugdatabase/view_bug?bug_id=7196857


15
如果实现不遵循规范,我会说这是实现中的错误。 - Anya Shenanigans
12
既然你有一个可靠重现问题的明确示例(至少在一些平台上),你考虑过提交缺陷报告了吗? - Joachim Sauer
4
是的,你应该毫不犹豫地提交一个错误报告。这是一个非常严重的错误! - Hot Licks
7
是的,我已经向Oracle发送了一个错误报告(错误ID为7196857),它将在几天内出现在公共的Oracle错误数据库中。 - Stanislav Poslavsky
6
我使用 Java 7 更新 7 的 64 位版本在 Windows 上尝试了一下,没有出现任何问题。 - Peter Lawrey
显示剩余24条评论
2个回答

42

在这里,我们面临着JIT编译器中的一个错误。编译器确定在分配后通过Arrays.fill(...)填充了分配的数组,但在分配和填充之间的使用检查有问题。因此,编译器执行了一个非法的优化 - 它跳过了对分配的数组进行清零的步骤。

这个错误已经被放在了Oracle的错误跟踪器中(bug id 7196857)。不幸的是,我没有等待Oracle对以下问题的任何澄清。据我所见,这个错误是特定于操作系统的:在64位Linux和Mac上绝对可以重现,但是根据评论,它在Windows上(对于相似版本的JDK)不定期地重现。另外,了解何时修复此错误将是很好的。

目前只有一个建议:如果您依赖于JLS来声明新数组,请不要使用JDK1.7.0_04或更高版本。

更新于10月5日:

在2012年10月4日发布的JDK 7u10(提前访问版本)的新Build 10中,这个bug至少在Linux操作系统上被修复了(我没有测试其他系统)。感谢@Makoto,他发现这个bug在Oracle的bug数据库中已经不再公开访问。不幸的是,我不知道Oracle为什么将其从公开访问中删除,但在Google的cache中可以找到。此外,这个bug引起了Redhat的注意:CVE标识符CVE-2012-4420bugzilla)和CVE-2012-4416bugzilla)已被分配给这个缺陷。

2
错误标识现在无效了 - 你能看一下吗? - Makoto
1
@Makoto 我很困惑,因为这个 bug 昨天还在 bug 数据库中。我不知道 Oracle 为什么从公共访问中删除了这个 bug。但是 Google 记得 http://webcache.googleusercontent.com/search?q=cache:Q0V_rKQNw5sJ:bugs.sun.com/bugdatabase/view_bug.do%3Fbug_id%3D7196857+&cd=5&hl=en&ct=clnk 此外,由于它可能导致 CVE,这个 bug 也被放置在 RedHat 的 bug 数据库中 https://bugzilla.redhat.com/show_bug.cgi?id=856124 - Stanislav Poslavsky

0

我在你的代码中做了一些更改。 这不是整数溢出的问题。看看代码,它会在运行时抛出异常

    int[] a;
    int n = 0;
    for (int i = 0; i < 100000000; ++i) {
        a = new int[10];
        for (int f : a) {
            if (f != 0) {
                throw new RuntimeException("Array just after allocation: " + Arrays.toString(a));
            }
        }
        for (int ii = 0, len = a.length; ii < len; ii++)
            a[ii] = 0;
        for (int j = 0; j < a.length; ++j)
            a[j] = Integer.MAX_VALUE - 1;
        for (int j = 0; j < a.length; ++j)
            n++;
    }

Windows 7 64位。JDK 64位1.7.0_07 - Roberto Mereghetti

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接