JRE错误?JTable包含某些字符串 - > ArrayIndexOutOfBoundsException

nto*_*rnl 5 java crash unicode swing fatal-error

用户报告某个YouTube视频导致我们的程序失败.经过调查,似乎将包含该视频标题的String添加到JTable会导致渲染代码中的某处出现ArrayIndexOutOfBoundsException.

我们已经在Windows XP,7和8以及Ubuntu上的Java 7u45和Java 8(b121)上测试并确认了这一点.

这是一个测试程序,展示了这个问题:

import javax.swing.*;
import java.awt.*;

public class TestJTableAIOOBE {
    private static final String TEXT = "\u0D38\u0D4D\u0D31\u0D4D\u0D31\u0D40\u0D32\u0D4D\u200D \u0D15\u0D31\u0D3F\u0D15\u0D4D\u0D15\u0D24\u0D4D\u0D24\u0D3F\u0D2F\u0D3F\u0D32\u0D4D\u200D \u0D2F\u0D47\u0D36\u0D41\u0D15\u0D4D\u0D30\u0D3F\u0D38\u0D4D\u0D24\u0D41\u0D35\u0D3F\u0D28\u0D4D\u0D31\u0D46 \u0D30\u0D42\u0D2A\u0D02 \u0D2A\u0D4D\u0D30\u0D24\u0D4D\u0D2F\u0D15\u0D4D\u0D37\u0D2A\u0D4D\u0D2A\u0D46\u0D1F\u0D4D\u0D1F\u0D41";

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                Font font = findFont();
                if (font == null) {
                    System.out.println("No suitable font found");
                    return;
                }
                System.out.println("Using font: " + font);
                JTable table = new JTable(new Object[][]{{TEXT}}, new Object[]{"title"});
                table.setFont(font);
                JFrame frame = new JFrame();
                frame.add(table);
                frame.pack();
                frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
                frame.setVisible(true);
            }
        });
    }

    private static Font findFont() {
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        for (Font font : ge.getAllFonts()) {
            if (font.canDisplayUpTo(TEXT) == -1) {
                return font.deriveFont(0, 12);
            }
        }
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

每次Swing尝试渲染文本时,此堆栈跟踪都会打印到stderr:

Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 48
    at sun.font.ExtendedTextSourceLabel.createCharinfo(ExtendedTextSourceLabel.java:814)
    at sun.font.ExtendedTextSourceLabel.getCharinfo(ExtendedTextSourceLabel.java:548)
    at sun.font.ExtendedTextSourceLabel.getLineBreakIndex(ExtendedTextSourceLabel.java:480)
    at java.awt.font.TextMeasurer.calcLineBreak(TextMeasurer.java:330)
    at java.awt.font.TextMeasurer.getLineBreakIndex(TextMeasurer.java:566)
    at java.awt.font.LineBreakMeasurer.nextOffset(LineBreakMeasurer.java:359)
    at java.awt.font.LineBreakMeasurer.nextOffset(LineBreakMeasurer.java:328)
    at sun.swing.SwingUtilities2.clipString(SwingUtilities2.java:472)
    at javax.swing.SwingUtilities.layoutCompoundLabelImpl(SwingUtilities.java:1023)
    at javax.swing.SwingUtilities.layoutCompoundLabel(SwingUtilities.java:892)
    at javax.swing.plaf.basic.BasicLabelUI.layoutCL(BasicLabelUI.java:94)
    at javax.swing.plaf.basic.BasicLabelUI.layout(BasicLabelUI.java:201)
    at javax.swing.plaf.basic.BasicLabelUI.paint(BasicLabelUI.java:164)
    at javax.swing.plaf.ComponentUI.update(ComponentUI.java:161)
    at javax.swing.JComponent.paintComponent(JComponent.java:777)
    at javax.swing.JComponent.paint(JComponent.java:1053)
    at javax.swing.CellRendererPane.paintComponent(CellRendererPane.java:151)
    at javax.swing.plaf.basic.BasicTableUI.paintCell(BasicTableUI.java:2115)
    at javax.swing.plaf.basic.BasicTableUI.paintCells(BasicTableUI.java:2016)
    at javax.swing.plaf.basic.BasicTableUI.paint(BasicTableUI.java:1812)
    at javax.swing.plaf.ComponentUI.update(ComponentUI.java:161)
    at javax.swing.JComponent.paintComponent(JComponent.java:777)
    at javax.swing.JComponent.paint(JComponent.java:1053)
    at javax.swing.JComponent.paintChildren(JComponent.java:886)
    at javax.swing.JComponent.paint(JComponent.java:1062)
    at javax.swing.JComponent.paintChildren(JComponent.java:886)
    at javax.swing.JComponent.paint(JComponent.java:1062)
    at javax.swing.JLayeredPane.paint(JLayeredPane.java:586)
    at javax.swing.JComponent.paintChildren(JComponent.java:886)
    at javax.swing.JComponent.paintToOffscreen(JComponent.java:5224)
    at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1532)
    at javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1455)
    at javax.swing.RepaintManager.paint(RepaintManager.java:1252)
    at javax.swing.JComponent.paint(JComponent.java:1039)
    at java.awt.GraphicsCallback$PaintCallback.run(GraphicsCallback.java:39)
    at sun.awt.SunGraphicsCallback.runOneComponent(SunGraphicsCallback.java:79)
    at sun.awt.SunGraphicsCallback.runComponents(SunGraphicsCallback.java:116)
    at java.awt.Container.paint(Container.java:1973)
    at java.awt.Window.paint(Window.java:3901)
    at javax.swing.RepaintManager$3.run(RepaintManager.java:822)
    at javax.swing.RepaintManager$3.run(RepaintManager.java:794)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:75)
    at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:794)
    at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:769)
    at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:718)
    at javax.swing.RepaintManager.access$1100(RepaintManager.java:62)
    at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1680)
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:744)
    at java.awt.EventQueue.access$400(EventQueue.java:97)
    at java.awt.EventQueue$3.run(EventQueue.java:697)
    at java.awt.EventQueue$3.run(EventQueue.java:691)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:75)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:714)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
Run Code Online (Sandbox Code Playgroud)

你能复制一下吗?字符串中的特殊性实际上导致了什么?它真的是一个JRE错误吗?我应该向Oracle报告吗?

nto*_*rnl 2

该错误于 2014 年 1 月向 Oracle 报告,三个月后,它以JDK-8041480 的形式出现在公共错误跟踪器中。该错误已于 2016 年 9 月在 Java 9 中修复。