Java : int 배열은 0이 아닌 요소로 초기화됩니다.


130

JLS에 따르면 int초기화 직후 배열을 0으로 채워야합니다. 그러나 나는 그렇지 않은 상황에 직면 해 있습니다. 이러한 동작은 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 최적화와 관련이 있습니다. 그러한 행동의 이유에 대한 아이디어가 있습니까?

업데이트 :
Gentoo Linux, Debian Linux (커널 3.0 버전) 및 MacOS Lion의 HotSpot 64 비트 서버 VM, Java 버전 1.7.0_04 ~ 1.7.0_10 에서이 동작이 나타납니다. 이 오류는 항상 위의 코드로 재현 할 수 있습니다. 32 비트 JDK 또는 Windows에서이 문제를 테스트하지 않았습니다. 이미 버그 보고서를 Oracle (버그 ID 7196857)에 보냈으며 며칠 후에 공개 Oracle 버그 데이터베이스에 나타납니다.

업데이트 :
Oracle은 공개 버그 데이터베이스에이 버그를 게시했습니다. http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7196857


15
이 사양에 따라 있지 않다면 나는 구현에 버그를 말하고 싶지만
Petesh

12
문제를 안정적으로 재현하는 잘 정의 된 예제가 있으므로 (적어도 일부 플랫폼에서는) 버그 신고 를 고려 했습니까?
Joachim Sauer

4
예, 가장 확실하게 버그 보고서를 제출해야합니다. 이것은 매우 심각한 버그입니다!
핫 릭

7
예, 이미 버그 보고서를 Oracle에 보냈으며 (버그 ID 7196857) 며칠 후에 공개 Oracle 버그 데이터베이스에 나타납니다.
Stanislav Poslavsky

6
Windows에서 Java 7 업데이트 7 64 비트로 시도했지만 문제가 없었습니다.
피터 로리

답변:


42

여기서 우리는 JIT 컴파일러의 버그에 직면했다. 컴파일러는의 할당 후 할당 된 배열이 채워져 Arrays.fill(...)있는지 확인하지만 할당과 채우기 사이의 사용 검사에 결함이 있습니다. 따라서 컴파일러는 잘못된 최적화를 수행합니다. 할당 된 배열의 0을 건너 뜁니다.

이 버그는 Oracle 버그 추적기 ( 버그 ID 7196857 )에 있습니다. 불행히도, 나는 다음 사항에 대한 오라클의 설명을 기다리지 않았습니다. 보시다시피,이 버그는 OS별로 다릅니다 .64 비트 Linux 및 Mac에서 절대적으로 재현 할 수 있지만 주석에서 볼 수 있듯이 Windows (JDK의 유사한 버전의 경우)에서는 정기적으로 재현하지 않습니다. 또한이 버그가 언제 수정되는지 아는 것이 좋습니다.

현재 조언 만 있습니다. 새로 선언 된 배열에 JLS를 사용하는 경우 JDK1.7.0_04 이상을 사용하지 마십시오.

10 월 5 일 업데이트 :

2012 년 10 월 4 일에 릴리스 된 JDK 7u10 (이전 액세스) 의 새로운 빌드 10 에서이 버그는 적어도 Linux OS에서 수정되었습니다 (다른 테스트는하지 않았습니다). @Makoto 덕분에이 버그는 더 이상 Oracle 버그 데이터베이스에서 공개 액세스 할 수 없다는 것을 알게되었습니다. 불행히도, 오라클이 공개 액세스에서 제거한 이유를 모르지만 Google 캐시 에서 사용할 수 있습니다 . 또한이 버그는 Redhat의 관심을 끌었습니다. CVE 식별자 CVE-2012-4420 ( bugzilla ) 및 CVE-2012-4416 ( bugzilla )이이 결함에 할당되었습니다.


2
버그 ID는 이제 유효하지 않습니다-이것으로 볼 수 있습니까?
Makoto

1
@Makoto 어제 버그 데이터베이스에 버그가 있었기 때문에 혼란스러워했습니다. Oracle이 공개 액세스에서이 버그를 제거한 이유를 모르겠습니다. 그러나 구글은 기억 webcache.googleusercontent.com/...을 그것이 CVE의로 이어질 수 있기 때문에이 버그는 또한, 레드햇 버그 데이터베이스에 배치했다 또한 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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.