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(在Gentoo Linux,Debian Linux(均为内核3.0版本)和MacOS Lion)上从1.7.0_04到1.7.0_10的Java版本上看到了此行为。始终可以使用上面的代码来重现此错误。我没有在32位JDK或Windows上测试此问题。我已经向Oracle发送了一个错误报告(错误ID 7196857),几天后它将出现在公共Oracle错误数据库中。

更新:
Oracle在其公共错误数据库中发布了此错误:http : //bugs.sun.com/bugdatabase/view_bug.do?bug_id=7196857


15
如果不遵循规范,我会说实施中的错误
Petesh 2012年

12
由于您有一个定义明确的示例(至少在某些平台上可以可靠地重现该问题),因此您是否考虑过提交错误
约阿希姆·绍尔

4
是的,您绝对应该提交错误报告。这是一个非常严重的错误!
热门点击2012年

7
是的,我已经向Oracle发送了错误报告(错误ID 7196857),几天后它将出现在公共Oracle错误数据库中。
Stanislav Poslavsky

6
我在Windows上使用Java 7 update 7 64位进行了尝试,但没有问题。
彼得·劳瑞

Answers:


42

在这里,我们面对的是JIT编译器中的错误。编译器确定在中分配后已填充已分配的数组Arrays.fill(...),但是分配和填充之间的使用检查不正确。因此,编译器执行非法优化-跳过分配的数组归零。

此错误放置在Oracle错误跟踪器中(错误ID 7196857)。不幸的是,我没有等待Oracle关于以下几点的任何澄清。如我所见,此错误是特定于操作系统的错误:它在64位Linux和Mac上绝对可重现,但是,正如我从评论中看到的那样,它在Windows上不定期复制(对于类似版本的JDK)。此外,很高兴知道何时会修复此错误。

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

10月5日更新:

在2012年10月4日发布的新JDK 7u10 Build 10(早期版本)中,此错误至少已在Linux OS上得到修复(我没有测试其他错误)。感谢@Makoto,他发现该错误不再对Oracle错误数据库开放供公众访问。不幸的是,我不知道Oracle从公共访问中删除它的原因,但是它在Google 缓存中可用。此外,此错误已引起Redhat的注意:为此漏洞分配了CVE标识符CVE-2012-4420bugzilla)和CVE-2012-4416bugzilla)。


2
错误ID现在无效-您可以调查一下吗?
Makoto 2012年

1
@Makoto我很困惑,因为该错误昨天在错误数据库中。我不知道Oracle从公共访问中删除此错误的原因。但是Google记得 webcache.googleusercontent.com/…另外,此错误也放置在RedHat错误数据库中,因为它可能导致CVE bugzilla.redhat.com/show_bug.cgi?id=856124
Stanislav Poslavsky 2012年

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 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.