Java: int array เริ่มต้นด้วยองค์ประกอบที่ไม่ใช่ศูนย์


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 ข้อผิดพลาดนี้สามารถทำซ้ำได้โดยใช้รหัสด้านบน ฉันไม่ได้ทดสอบปัญหานี้กับ JDK 32 บิตหรือบน Windows ฉันได้ส่งรายงานข้อบกพร่องไปยัง Oracle แล้ว (รหัสข้อผิดพลาด 7196857) และจะปรากฏในฐานข้อมูลข้อบกพร่องของ Oracle สาธารณะในอีกไม่กี่วัน

อัปเดต:
Oracle เผยแพร่ข้อบกพร่องนี้ที่ฐานข้อมูลข้อผิดพลาดสาธารณะ: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7196857


15
ฉันจะบอกว่ามีข้อผิดพลาดในการใช้งานหากไม่เป็นไปตามข้อกำหนด
Petesh

12
เนื่องจากคุณมีตัวอย่างที่กำหนดไว้อย่างชัดเจนซึ่งทำให้เกิดปัญหาขึ้นอย่างน่าเชื่อถือ (อย่างน้อยก็ในบางแพลตฟอร์ม) คุณจึงพิจารณายื่นข้อบกพร่องหรือไม่
Joachim Sauer

4
ใช่คุณควรยื่นรายงานข้อบกพร่องอย่างแน่นอน นี่เป็นข้อบกพร่องที่ร้ายแรงมาก!
Hot Licks

7
ใช่ฉันได้ส่งรายงานข้อบกพร่องไปยัง Oracle แล้ว (รหัสข้อผิดพลาด 7196857) และจะปรากฏในฐานข้อมูลข้อผิดพลาด Oracle สาธารณะในอีกไม่กี่วัน
Stanislav Poslavsky

6
ฉันลองใช้กับ Java 7 update 7 64-bit บน Windows แล้วก็ไม่มีปัญหา
Peter Lawrey

คำตอบ:


42

ที่นี่เรากำลังเผชิญกับข้อผิดพลาดในคอมไพเลอร์ JIT คอมไพลเลอร์พิจารณาว่าอาร์เรย์ที่จัดสรรถูกเติมหลังจากการจัดสรรArrays.fill(...)แต่การตรวจสอบการใช้งานระหว่างการจัดสรรและการเติมมีข้อผิดพลาด ดังนั้นคอมไพเลอร์จึงทำการเพิ่มประสิทธิภาพที่ผิดกฎหมาย - มันข้ามการเป็นศูนย์ของอาร์เรย์ที่จัดสรร

จุดบกพร่องนี้อยู่ในตัวติดตามข้อบกพร่องของ Oracle ( รหัสข้อผิดพลาด 7196857 ) น่าเสียดายที่ฉันไม่ได้รอคำชี้แจงใด ๆ จาก Oracle เกี่ยวกับประเด็นต่อไปนี้ อย่างที่ฉันเห็นข้อผิดพลาดนี้เป็นข้อผิดพลาดเฉพาะระบบปฏิบัติการ: สามารถทำซ้ำได้อย่างแน่นอนบน Linux และ Mac 64 บิต แต่อย่างที่ฉันเห็นจากความคิดเห็นมันไม่ได้เกิดซ้ำบน Windows เป็นประจำ (สำหรับ JDK เวอร์ชันที่คล้ายกัน) นอกจากนี้จะเป็นการดีที่จะทราบว่าเมื่อใดที่ข้อบกพร่องนี้จะได้รับการแก้ไข

มีเพียงคำแนะนำในขณะนี้: อย่าใช้ JDK1.7.0_04 หรือใหม่กว่าหากคุณใช้ JLS สำหรับอาร์เรย์ที่ประกาศใหม่

อัปเดตวันที่ 5 ตุลาคม:

ในBuild 10ใหม่ของ JDK 7u10 (ทดลองใช้ก่อนเปิดตัว) เมื่อวันที่ 4 ตุลาคม 2012 ข้อบกพร่องนี้ได้รับการแก้ไขอย่างน้อยสำหรับ Linux OS (ฉันไม่ได้ทดสอบสำหรับตัวอื่น) ขอบคุณ @Makoto ที่พบว่าข้อบกพร่องนี้ไม่สามารถเข้าถึงได้แบบสาธารณะในฐานข้อมูลข้อผิดพลาด Oracle อีกต่อไป แต่น่าเสียดายที่ผมไม่ทราบว่าด้วยเหตุผลออราเคิลลบออกจากการเข้าถึงของประชาชน แต่ก็สามารถใช้ได้ใน Google แคช นอกจากนี้ข้อบกพร่องนี้ยังได้รับความสนใจจาก Redhat: ตัวระบุCVE CVE-2012-4420 ( bugzilla ) และCVE-2012-4416 ( bugzilla ) ถูกกำหนดให้กับข้อบกพร่องนี้


2
ตอนนี้รหัสข้อบกพร่องไม่ถูกต้องคุณช่วยตรวจสอบได้ไหม
Makoto

1
@ Makoto ฉันสับสนเนื่องจากข้อผิดพลาดนี้อยู่ในฐานข้อมูลข้อผิดพลาดเมื่อวานนี้ ฉันไม่ทราบเหตุผลที่ Oracle ลบข้อบกพร่องนี้ออกจากการเข้าถึงแบบสาธารณะ แต่ Google จำ webcache.googleusercontent.com/…นอกจากนี้ข้อผิดพลาดนี้ยังอยู่ในฐานข้อมูลข้อบกพร่องของ RedHat เนื่องจากอาจนำไปสู่ ​​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 bit 1.7.0_07
Roberto Mereghetti
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.