JDK-6921591 : NPE when rendering JLabel with specific unicode characters
  • Type: Enhancement
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 6u10,6u17,6u18
  • Priority: P3
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_xp,windows_vista
  • CPU: x86
  • Submitted: 2010-02-01
  • Updated: 2010-10-08
  • Resolved: 2010-10-08
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7
7Resolved
Related Reports
Duplicate :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.6.0_13"
Java(TM) SE Runtime Environment (build 1.6.0_13-b03)
Java HotSpot(TM) Client VM (build 11.3-b02, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 5.2.3790]

Linux 2.6.31 #1 SMP Tue Nov 17 12:34:32 CET 2009 x86_64 GNU/Linux


A DESCRIPTION OF THE PROBLEM :
Rendering a JLabel which contains specific unicode characters in text results in a NullPointerException.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached test code with 6u17 or 6u18-ea-b04.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Expect return code 0 (as with 6u13).
ACTUAL -
NullPointerException (see below), return code 1

ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread "main" java.lang.NullPointerException
	at java.util.Hashtable.put(Hashtable.java:394)
	at sun.font.PhysicalStrike.getGlyphPoint(PhysicalStrike.java:112)
	at sun.font.SunLayoutEngine.nativeLayout(Native Method)
	at sun.font.SunLayoutEngine.layout(SunLayoutEngine.java:133)
	at sun.font.GlyphLayout$EngineRecord.layout(GlyphLayout.java:648)
	at sun.font.GlyphLayout.layout(GlyphLayout.java:447)
	at sun.font.ExtendedTextSourceLabel.createGV(ExtendedTextSourceLabel.java:308)
	at sun.font.ExtendedTextSourceLabel.getGV(ExtendedTextSourceLabel.java:294)
	at sun.font.ExtendedTextSourceLabel.createLogicalBounds(ExtendedTextSourceLabel.java:208)
	at sun.font.ExtendedTextSourceLabel.getAdvance(ExtendedTextSourceLabel.java:117)
	at java.awt.font.TextLine.init(TextLine.java:264)
	at java.awt.font.TextLine.<init>(TextLine.java:110)
	at java.awt.font.TextLine.fastCreateTextLine(TextLine.java:952)
	at java.awt.font.TextLayout.fastInit(TextLayout.java:585)
	at java.awt.font.TextLayout.<init>(TextLayout.java:374)
	at sun.font.FontDesignMetrics.stringWidth(FontDesignMetrics.java:465)
	at sun.swing.SwingUtilities2.stringWidth(SwingUtilities2.java:338)
	at javax.swing.SwingUtilities.layoutCompoundLabelImpl(SwingUtilities.java:984)
	at javax.swing.SwingUtilities.layoutCompoundLabel(SwingUtilities.java:870)
	at javax.swing.plaf.basic.BasicLabelUI.layoutCL(BasicLabelUI.java:76)
	at javax.swing.plaf.basic.BasicLabelUI.layout(BasicLabelUI.java:184)
	at javax.swing.plaf.basic.BasicLabelUI.paint(BasicLabelUI.java:147)
	at javax.swing.plaf.ComponentUI.update(ComponentUI.java:143)
	at javax.swing.JComponent.paintComponent(JComponent.java:751)
	at Bug72846$1.setText(Bug72846.java:18)
	at Bug72846.test(Bug72846.java:24)
	at Bug72846$2.run(Bug72846.java:32)
	at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:199)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:597)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
	at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.awt.Font;
import java.awt.image.BufferedImage;
import javax.swing.JLabel;
import org.junit.Test;

public class Bug72846 {

	@Test
	public void test() {
		final BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
		final JLabel jLabel = new JLabel() {

			@Override
			public void setText(final String text) {
				super.setText(text);
				paintComponent(image.getGraphics());
			}

		};
		jLabel.setFont(Font.decode("Dialog"));
		final char[] chars = Character.toChars(2375);
		jLabel.setText(String.valueOf(chars));
	}

}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Code succeeds with 6u13, fails with 6u18
Additional report:

FULL PRODUCT VERSION :
java version "1.6.0_18"
Java(TM) SE Runtime Environment (build 1.6.0_18-b07)
Java HotSpot(TM) 64-Bit Server VM (build 16.0-b13, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.0.6002] Japanese locale

A DESCRIPTION OF THE PROBLEM :
In Swing applications, NPE occurs at sun.font.PhysicalStrike.getGlyphPoint() method  if a specific (unlikely) Unicode text is to be shown. Former Java SE 6 releases, at least 6u3,  seem to be not affected.
Since somewhere between 6u3 and 6u12, Java_sun_font_TrueTypeFont_getGlyphPoint() defined in j2se\src\share\native\sun\font\scalerMethods.c was updeted to include a code path to return NULL, which is not expected by the caller, sun.font.PhysicalStrike.getGlyphPoint().

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached program on later versions of Java SE 6 runtime.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Do not die.
ACTUAL -
Dies with NPE.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread "main" java.lang.NullPointerException
        at java.util.Hashtable.put(Hashtable.java:394)
        at sun.font.PhysicalStrike.getGlyphPoint(PhysicalStrike.java:112)
        at sun.font.SunLayoutEngine.nativeLayout(Native Method)
        at sun.font.SunLayoutEngine.layout(SunLayoutEngine.java:133)
        at sun.font.GlyphLayout$EngineRecord.layout(GlyphLayout.java:648)
        at sun.font.GlyphLayout.layout(GlyphLayout.java:447)
        at sun.font.ExtendedTextSourceLabel.createGV(ExtendedTextSourceLabel.java:308)
        at sun.font.ExtendedTextSourceLabel.getGV(ExtendedTextSourceLabel.java:294)
        at sun.font.ExtendedTextSourceLabel.createLogicalBounds(ExtendedTextSourceLabel.java:208)
        at sun.font.ExtendedTextSourceLabel.getAdvance(ExtendedTextSourceLabel.java:117)
        at java.awt.font.TextLine.init(TextLine.java:264)
        at java.awt.font.TextLine.<init>(TextLine.java:110)
        at java.awt.font.TextLine.fastCreateTextLine(TextLine.java:952)
        at java.awt.font.TextLayout.fastInit(TextLayout.java:585)
        at java.awt.font.TextLayout.<init>(TextLayout.java:374)
        at sun.font.FontDesignMetrics.stringWidth(FontDesignMetrics.java:465)
        at sun.swing.SwingUtilities2.stringWidth(SwingUtilities2.java:340)
        at javax.swing.SwingUtilities.layoutCompoundLabelImpl(SwingUtilities.java:984)
        at javax.swing.SwingUtilities.layoutCompoundLabel(SwingUtilities.java:870)
        at javax.swing.plaf.basic.BasicLabelUI.layoutCL(BasicLabelUI.java:76)
        at javax.swing.plaf.basic.BasicLabelUI.getPreferredSize(BasicLabelUI.java:221)
        at javax.swing.JComponent.getPreferredSize(JComponent.java:1634)
        at java.awt.BorderLayout.preferredLayoutSize(BorderLayout.java:702)
        at java.awt.Container.preferredSize(Container.java:1599)
        at java.awt.Container.getPreferredSize(Container.java:1584)
        at javax.swing.JComponent.getPreferredSize(JComponent.java:1636)
        at javax.swing.JRootPane$RootLayout.preferredLayoutSize(JRootPane.java:907)
        at java.awt.Container.preferredSize(Container.java:1599)
        at java.awt.Container.getPreferredSize(Container.java:1584)
        at javax.swing.JComponent.getPreferredSize(JComponent.java:1636)
        at java.awt.BorderLayout.preferredLayoutSize(BorderLayout.java:702)
        at java.awt.Container.preferredSize(Container.java:1599)
        at java.awt.Container.getPreferredSize(Container.java:1584)
        at java.awt.Window.pack(Window.java:706)
        at SwingDeath.main(swingdeath.java:11)


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import javax.swing.*;

public class SwingDeath {
	public static void main(String argv[])
	{
		String t = "\\U+0901-\u0901"; // ill Unicode text
		JFrame frame = new JFrame("Swing Death");
		final JLabel label = new JLabel(t);
		frame.getContentPane().add(label);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.pack();
		// NOTREACHED
		frame.setVisible(true);
	}
}

---------- END SOURCE ----------

Comments
EVALUATION I've closed this as a duplicate of 6921591. A new bug has been filed to track the robustness issues which are not reproducible with any provided test case and can be addressed in a JDK 7 time frame.
08-10-2010

EVALUATION It turns out that ExtendedTextLabel may return -1 for line break position: ==== /** * Return the logical index of the character, starting with the character at * logicalStart, whose accumulated advance exceeds width. If the advances of * all characters do not exceed width, return getNumCharacters. If width is * less than zero, return logicalStart - 1. */ public abstract int getLineBreakIndex(int logicalStart, float width); ==== That cause TextMeasurer.getLineBreakIndex() to return -1 too and this causes out of bounds exception. Even if T2K code will be fixed to return non null objects it is still legitimate case that overall width is negative. TextMeasurer logic needs to be improved to handle it. Perhaps the fix could be to check return value of tlc.getLineBreakIndex in the TextMeasurer.calcLineBreak() and interpret is as "full string can be drawn before line break"?
13-07-2010

EVALUATION I am getting following exception with latest JDK7 (b99+): Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: -1 at java.awt.font.LineBreakMeasurer.nextOffset(LineBreakMeasurer.java:365) at java.awt.font.LineBreakMeasurer.nextOffset(LineBreakMeasurer.java:328) at sun.swing.SwingUtilities2.clipString(SwingUtilities2.java:467) at javax.swing.SwingUtilities.layoutCompoundLabelImpl(SwingUtilities.java:1017) at javax.swing.SwingUtilities.layoutCompoundLabel(SwingUtilities.java:886) 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:778) at Bug$1$1.setText(Bug.java:17) at Bug$1.run(Bug.java:22) at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:251) at java.awt.EventQueue.dispatchEvent(EventQueue.java:649) at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:255) at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:170) at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:160) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:155) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:147) at java.awt.EventDispatchThread.run(EventDispatchThread.java:136) import java.awt.Font; import java.awt.image.BufferedImage; import javax.swing.JLabel; import javax.swing.SwingUtilities; public class Bug { public static void main(String a[]) { SwingUtilities.invokeLater(new Runnable() { public void run() { final BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB); final JLabel jLabel = new JLabel() { @Override public void setText(final String text) { super.setText(text); paintComponent(image.getGraphics()); } }; jLabel.setFont(Font.decode("Dialog")); final char[] chars = Character.toChars(2375); jLabel.setText(String.valueOf(chars)); } }); } } And this is my testcase:
13-07-2010

EVALUATION Technically, this NPE is manifestation of 6921593 and after fix for 6921591 none of these testcases will be able to reproduce the problem. However, deeper issue is that t2k will be returning null objects on error and we do not handle this gracefully. Perhaps t2k glue layer needs to be changed to return more meaningful values, like (0, 0) point in this case.
02-02-2010

EVALUATION The following simpler program also demonstrates the NPE, starting from JDk 6u17 b01 import java.awt.*; import java.awt.font.*; public class tl { public static void main(String args[]) { Font font = new Font("Lucida Sans", Font.PLAIN, 12); FontRenderContext frc = new FontRenderContext(null, false, false); TextLayout tl = new TextLayout("\u0947", font, frc); } }
01-02-2010