JDK-6404410 : REGRESSION: GridBagLayout throws AIOOBException if columnWidths.length > number
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 6
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2006-03-27
  • Updated: 2011-01-19
  • Resolved: 2006-04-15
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 6
6 b81Fixed
Related Reports
Duplicate :  
Relates :  
Description
A DESCRIPTION OF THE REGRESSION :
GridBagLayout throws an ArrayIndexOutOfBoundsException if GridBagLayout.columnWidths or GridBagLayout.rowHeights is set and the container has no children. It also throws an ArrayIndexOutOfBoundsException if GridBagLayout.columnWidths.length is at least twice as large as the number of columns. E.g. GridBagLayout.columnWidths = new int[] {0, 0, 0} and there is only one component in column 0.

The JavaDoc for GridBagLayout.columnWidths (and rowHeights) says:
If columnWidths has more elements than the number of columns, columns are ADDED to the gridbag to match the number of elements in columnWidth.


Seems that GridBagLayout has been optimized to reduce used memory. In Java5 all internal arrays are 512 elements long and all works fine. In Java 6 b72, the internal arrays get minimum necessary sizes, but some internal arrays are wrongly sized, which cause the trouble.


SUGGESTED FIX:

In GridBagLayout.java at line 1343 change
            r.weightX = new double[maximumArrayYIndex];
            r.weightY = new double[maximumArrayXIndex];
            r.minWidth = new int[maximumArrayYIndex];
            r.minHeight = new int[maximumArrayXIndex];
to
            r.weightX = new double[layoutWidth];
            r.weightY = new double[layoutHeight];
            r.minWidth = new int[layoutWidth];
            r.minHeight = new int[layoutHeight];


maximumArray[X/Y]Index does not take into account that columnWidths/rowHeights may be larger than the number of columns/rows. I also think that maximumArray[X/Y]Index is larger than necessary because it is doubled in line 1062 (multiplicated with EMPIRICMULTIPLIER).

BTW it is a little bit confusing that maximumArray**Y**Index is used as size for r.weight**X**


REPRODUCIBLE TESTCASE OR STEPS TO REPRODUCE:
The first test case shows a empty frame of size 100x100 pixel when using Java 5 and throws the above exception when using Java 6.

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

public class GridBagLayoutRegression1
{
	public static void main( String[] args ) {
		System.out.println(System.getProperty("java.vm.version"));
		GridBagLayout layout = new GridBagLayout();
		layout.columnWidths = new int[] {100};
		layout.rowHeights = new int[] {100};

		JPanel panel = new JPanel(layout);
		
		JFrame frame = new JFrame("GridBagLayoutRegression");
		frame.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
		frame.add(panel);
		frame.pack();
		frame.setVisible(true);
	}
}


The second test case shows a frame of size 100x100 pixel with a label in the upper-left corner when using Java 5 and throws the above exception when using Java 6.

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

public class GridBagLayoutRegression2
{
	public static void main( String[] args ) {
		System.out.println(System.getProperty("java.vm.version"));
		GridBagLayout layout = new GridBagLayout();
		layout.columnWidths = new int[] {0, 0, 100};
		layout.rowHeights = new int[] {0, 0, 100};
		layout.columnWeights = new double[] {0.0, 0.0, 0.01};
		layout.rowWeights = new double[] {0.0, 0.0, 0.01};

		JPanel panel = new JPanel(layout);
		JLabel label = new JLabel("text");
		panel.add(label, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0,
			GridBagConstraints.CENTER, GridBagConstraints.BOTH,
			new Insets(0, 0, 0, 0), 0, 0));
		
		JFrame frame = new JFrame("GridBagLayoutRegression");
		frame.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
		frame.add(panel);
		frame.pack();
		frame.setVisible(true);
	}
}


RELEASE LAST WORKED:
5.0 Update 6

RELEASE TEST FAILS:
mustang-b72

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
If columnWidths/rowHeights has more elements than the number of columns/rows, columns/rows should be added.
ACTUAL -
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException
	at java.lang.System.arraycopy(Native Method)
	at java.awt.GridBagLayout.GetLayoutInfo(GridBagLayout.java:1357)
	at java.awt.GridBagLayout.getLayoutInfo(GridBagLayout.java:944)
	at java.awt.GridBagLayout.preferredLayoutSize(GridBagLayout.java:764)
	at java.awt.Container.preferredSize(Container.java:1558)
	at java.awt.Container.getPreferredSize(Container.java:1543)
	at javax.swing.JComponent.getPreferredSize(JComponent.java:1653)
	at java.awt.BorderLayout.preferredLayoutSize(BorderLayout.java:702)
	at java.awt.Container.preferredSize(Container.java:1558)
	at java.awt.Container.getPreferredSize(Container.java:1543)
	at javax.swing.JComponent.getPreferredSize(JComponent.java:1653)
	at javax.swing.JRootPane$RootLayout.preferredLayoutSize(JRootPane.java:860)
	at java.awt.Container.preferredSize(Container.java:1558)
	at java.awt.Container.getPreferredSize(Container.java:1543)
	at javax.swing.JComponent.getPreferredSize(JComponent.java:1653)
	at java.awt.BorderLayout.preferredLayoutSize(BorderLayout.java:702)
	at java.awt.Container.preferredSize(Container.java:1558)
	at java.awt.Container.getPreferredSize(Container.java:1543)
	at java.awt.Window.pack(Window.java:558)
	at GridBagLayoutRegression1.main(GridBagLayoutRegression1.java:18)


APPLICATION NAME: JFormDesignerOBSERVED APPLICATION IMPACT:
JFormDesigner is a Swing GUI designer that supports GridBagLayout. When creating a JPanel with GridBagLayout, JFormDesigner creates empty columns and rows to make it easy for the user to add components. It does this by setting
  GridBagLayout.columnWidths = new int[] {20, 20}
  GridBagLayout.rowHeights= new int[] {20, 20, 20}
which throws above exception and makes JFormDesigner hard to use.

JFormDesigner also allows adding empty columns/rows and setting minimum width/height for them. The generated code uses GridBagLayout.columnWidths and rowHeights for this. So this bug may also break forms designed by JFormDesigner users.

Release Regression From : mustang
The above release value was the last known release where this 
bug was known to work. Since then there has been a regression.

Comments
EVALUATION GBL logic fails if there is less Components in Container to layout. This happens because private long[] preInitMaximumArraySizes(Container parent) does count only components actually being added into Container. Otherwise it returns maximumArray[X|Y]Index that isn't sufficient for arrayCopy(). For example: System.arraycopy(columnWidths, 0, r.minWidth, 0, columnWidths.length); where columnWidths has length larger then r.minWidth. So sort it out we may get Math.max(empiric size, user-defined size) and register arrays with that resulting value. We still have to calculate that optimistic size to keep following changes alive: Delta 1.68: Fixed: 5055696 REGRESSION: GridBagLayout throws ArrayIndexOutOfBoundsExceptions 5005945 GridBagLayout uses unneccessary loops 4254022 PERF: GridBagLayout inefficiency 5050375 Infinit loop in panel layout
27-03-2006