United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-4623196 : GridBagLayout.minimumLayoutSize throws unexpected AIOOBE

Details
Type:
Bug
Submit Date:
2002-01-14
Status:
Closed
Updated Date:
2005-12-01
Project Name:
JDK
Resolved Date:
2005-04-18
Component:
client-libs
OS:
solaris_2.5
Sub-Component:
java.awt
CPU:
sparc
Priority:
P4
Resolution:
Fixed
Affected Versions:
6
Fixed Versions:

Related Reports
Relates:

Sub Tasks

Description
Name: idR10193			Date: 01/14/2002


Call to the method minimumLayoutSize of GridBagLayout leads to
unexpected java.lang.ArrayIndexOutOfBoundsException (actually it 
happends in GetLayoutInfo).

============================== Start of addLC.java =======================
import java.awt.*;

public class addLC {

    public static void main(String argv[]) {
        GridBagLayout gbl = new GridBagLayout();
    
        Container parent = new Container();
        parent.setSize(801, 601);
        parent.setLayout(gbl);
    
        GridBagConstraints gbc = new GridBagConstraints();

        gbc.gridx = 0;
        gbc.gridy = Integer.MAX_VALUE;
        gbc.gridwidth = Integer.MAX_VALUE;
        gbc.gridheight = 0;
        gbc.anchor = GridBagConstraints.CENTER;
        gbc.weightx = 0;
        gbc.weighty = Double.MAX_VALUE;
        gbc.fill = GridBagConstraints.NONE;
        gbc.ipadx = 0;
        gbc.ipady = Integer.MAX_VALUE;
        Insets insets = new Insets(0, 1, 2, 3);
    
        Component comp = new Component(){};
        comp.setSize(40, 30);
    
        parent.add(comp, gbc);
    
        Dimension new_sz = gbl.minimumLayoutSize(parent);

        System.out.println(new_sz);
    }
}
============================== End of AddLC.java =======================
Output under JDK version "1.4.0-rc-b91" ===============================

~/bugs;
javac addLC.java;java addLC
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException
        at java.awt.GridBagLayout.GetLayoutInfo(GridBagLayout.java:872)
        at java.awt.GridBagLayout.getLayoutInfo(GridBagLayout.java:791)
        at java.awt.GridBagLayout.minimumLayoutSize(GridBagLayout.java:640)
        at addLC.main(addLC.java:31)
~/bugs;
=======================================================================

======================================================================

                                    

Comments
SUGGESTED FIX

------- GridBagLayout.java -------
*** /tmp/geta21425      Fri Nov 14 11:51:21 2003
--- /tmp/getb21425      Fri Nov 14 11:51:21 2003
***************
*** 8,13 ****
--- 8,14 ----
  
  import java.util.Hashtable;
  import java.util.Vector;
+ import java.util.ArrayList;
  
  class GridBagLayoutInfo implements java.io.Serializable {
    int width, height;          /* number of cells horizontally, vertically */
***************
*** 18,28 ****
    double weightY[];           /* largest weight in each row */
  
    GridBagLayoutInfo () {
!     minWidth = new int[GridBagLayout.MAXGRIDSIZE];
!     minHeight = new int[GridBagLayout.MAXGRIDSIZE];
!     weightX = new double[GridBagLayout.MAXGRIDSIZE];
!     weightY = new double[GridBagLayout.MAXGRIDSIZE];
    }
  }
  
  /**
--- 19,35 ----
    double weightY[];           /* largest weight in each row */
  
    GridBagLayoutInfo () {
!       this(GridBagLayout.MAXGRIDSIZE, GridBagLayout.MAXGRIDSIZE);
    }
+   GridBagLayoutInfo(int width, int height) {
+     this.width = width;
+     this.height = height;
+ 
+     minWidth = new int[width];
+     minHeight = new int[height];
+     weightX = new double[width];
+     weightY = new double[height];
+   }
  }
  
  /**
***************
*** 269,275 ****
   * }
   * </pre></blockquote><hr>
   * <p>
!  * @version 1.5, 16 Nov 1995
   * @author Doug Stein
   * @see       java.awt.GridBagConstraints
   * @see       java.awt.ComponentOrientation
--- 276,282 ----
   * }
   * </pre></blockquote><hr>
   * <p>
!  * @version   %I%, %G%
   * @author Doug Stein
   * @see       java.awt.GridBagConstraints
   * @see       java.awt.ComponentOrientation
***************
*** 279,286 ****
                                      java.io.Serializable {
  
      /**
!      * The maximum number of grid positions (both horizontally and
!      * vertically) that can be laid out by the grid bag layout.
       */
    protected static final int MAXGRIDSIZE = 512;
  
--- 286,294 ----
                                      java.io.Serializable {
  
      /**
!      * As of 1.5, this field is no longer used.  Previously, this was 
!      * the maximum number of grid positions (both horizontal and 
!      * vertical) that could be laid out by the grid bag layout.  
       */
    protected static final int MAXGRIDSIZE = 512;
  
***************
*** 819,824 ****
--- 827,840 ----
          return GetLayoutInfo(parent, sizeflag);
      }
  
+     private static final Integer ZERO = new Integer(0);
+     private static void ensureSize(ArrayList<Integer> arrayList, int size) {
+         arrayList.ensureCapacity(size);
+         while (arrayList.size() < size) {
+             arrayList.add(ZERO);
+         }
+     }
+ 
      /**
       * This method is obsolete and supplied for backwards
       * compatability only; new code should call {@link
***************
*** 829,844 ****
       */
    protected GridBagLayoutInfo GetLayoutInfo(Container parent, int sizeflag) {
     synchronized (parent.getTreeLock()) {
!     GridBagLayoutInfo r = new GridBagLayoutInfo();
      Component comp;
      GridBagConstraints constraints;
      Dimension d;
      Component components[] = parent.getComponents();
  
      int compindex, i, j, k, px, py, pixels_diff, nextSize;
      int curX, curY, curWidth, curHeight, curRow, curCol;
      double weight_diff, weight, start, size;
      int xMax[], yMax[];
  
      /*
       * Pass #1
--- 845,863 ----
       */
    protected GridBagLayoutInfo GetLayoutInfo(Container parent, int sizeflag) {
     synchronized (parent.getTreeLock()) {
!     GridBagLayoutInfo r;
      Component comp;
      GridBagConstraints constraints;
      Dimension d;
      Component components[] = parent.getComponents();
  
+     int layoutWidth, layoutHeight;
      int compindex, i, j, k, px, py, pixels_diff, nextSize;
      int curX, curY, curWidth, curHeight, curRow, curCol;
      double weight_diff, weight, start, size;
      int xMax[], yMax[];
+     ArrayList<Integer> xMaxArray = new ArrayList<Integer>(components.length);
+     ArrayList<Integer> yMaxArray = new ArrayList<Integer>(components.length);
  
      /*
       * Pass #1
***************
*** 847,856 ****
       * zero or negative widths and heights).
       */
  
!     r.width = r.height = 0;
      curRow = curCol = -1;
-     xMax = new int[MAXGRIDSIZE];
-     yMax = new int[MAXGRIDSIZE];
  
      for (compindex = 0 ; compindex < components.length ; compindex++) {
        comp = components[compindex];
--- 866,873 ----
       * zero or negative widths and heights).
       */
  
!     layoutWidth = layoutHeight = 0; 
      curRow = curCol = -1;
  
      for (compindex = 0 ; compindex < components.length ; compindex++) {
        comp = components[compindex];
***************
*** 878,885 ****
        }
        if (curX < 0) {
        px = 0;
!       for (i = curY; i < (curY + curHeight); i++)
!         px = Math.max(px, xMax[i]);
  
        curX = px - curX - 1;
        if(curX < 0)
--- 895,904 ----
        }
        if (curX < 0) {
        px = 0;
!         ensureSize(xMaxArray, curY + curHeight); 
!         for (i = curY; i < (curY + curHeight); i++) { 
!           px = Math.max(px, xMaxArray.get(i).intValue()); 
!         }
  
        curX = px - curX - 1;
        if(curX < 0)
***************
*** 887,894 ****
        }
        else if (curY < 0) {
        py = 0;
!       for (i = curX; i < (curX + curWidth); i++)
!         py = Math.max(py, yMax[i]);
  
        curY = py - curY - 1;
        if(curY < 0)
--- 906,915 ----
        }
        else if (curY < 0) {
        py = 0;
!     ensureSize(yMaxArray, curX + curWidth);
!       for (i = curX; i < (curX + curWidth); i++) {
!         py = Math.max(py, yMaxArray.get(i).intValue());
!     }
  
        curY = py - curY - 1;
        if(curY < 0)
***************
*** 896,907 ****
        }
  
        /* Adjust the grid width and height */
!       for (px = curX + curWidth; r.width < px; r.width++);
!       for (py = curY + curHeight; r.height < py; r.height++);
  
!       /* Adjust the xMax and yMax arrays */
!       for (i = curX; i < (curX + curWidth); i++) { yMax[i] = py; }
!       for (i = curY; i < (curY + curHeight); i++) { xMax[i] = px; }
  
        /* Cache the current slave's size. */
        if (sizeflag == PREFERREDSIZE)
--- 917,934 ----
        }
  
        /* Adjust the grid width and height */
!       for (px = curX + curWidth; layoutWidth < px; layoutWidth++); 
!       for (py = curY + curHeight; layoutHeight < py; layoutHeight++);
  
!       /* Adjust xMaxArray and yMaxArray */
!       ensureSize(yMaxArray, curX + curWidth); 
!       for (i = curX; i < (curX + curWidth); i++) { 
!           yMaxArray.set(i, new Integer(py)); 
!       }
!       ensureSize(xMaxArray, curY + curHeight);
!       for (i = curY; i < (curY + curHeight); i++) {
!           xMaxArray.set(i, new Integer(px));
!       }
  
        /* Cache the current slave's size. */
        if (sizeflag == PREFERREDSIZE)
***************
*** 928,938 ****
      /*
       * Apply minimum row/column dimensions
       */
!     if (columnWidths != null && r.width < columnWidths.length)
!       r.width = columnWidths.length;
!     if (rowHeights != null && r.height < rowHeights.length)
!       r.height = rowHeights.length;
  
      /*
       * Pass #2
       *
--- 955,970 ----
      /*
       * Apply minimum row/column dimensions
       */
!     if (columnWidths != null && layoutWidth < columnWidths.length)
!         layoutWidth = columnWidths.length;
!     if (rowHeights != null && layoutHeight < rowHeights.length)
!         layoutHeight = rowHeights.length;
  
+     // Now that we know the grid's width and height, create the
+     // GridBagLayoutInfo.
+     r = new GridBagLayoutInfo(layoutWidth, layoutHeight);
+ 
+ 
      /*
       * Pass #2
       *
***************
*** 943,950 ****
       */
  
      curRow = curCol = -1;
!     xMax = new int[MAXGRIDSIZE];
!     yMax = new int[MAXGRIDSIZE];
  
      for (compindex = 0 ; compindex < components.length ; compindex++) {
        comp = components[compindex];
--- 975,982 ----
       */
  
      curRow = curCol = -1;
!     xMax = new int[layoutHeight];
!     yMax = new int[layoutWidth];
  
      for (compindex = 0 ; compindex < components.length ; compindex++) {
        comp = components[compindex];

###@###.### 2003-11-14


*** /tmp/geta17605	 14 11:44:43 2005
--- GridBagLayout.java	 10 15:35:07 2005
***************
*** 840,846 ****
       * maximumArrayXIndex and maximumArrayYIndex.
       */
  
!     private Point preInitMaximumArraySizes(Container parent){
          Component components[] = parent.getComponents();
          Component comp;
          GridBagConstraints constraints;
--- 840,846 ----
       * maximumArrayXIndex and maximumArrayYIndex.
       */
  
!     private long[]  preInitMaximumArraySizes(Container parent){
          Component components[] = parent.getComponents();
          Component comp;
          GridBagConstraints constraints;
***************
*** 848,854 ****
          int curWidth, curHeight;
          int preMaximumArrayXIndex = 0;
          int preMaximumArrayYIndex = 0;
! 
          for (int compId = 0 ; compId < components.length ; compId++) {
              comp = components[compId];
              if (!comp.isVisible()) {
--- 848,855 ----
          int curWidth, curHeight;
          int preMaximumArrayXIndex = 0;
          int preMaximumArrayYIndex = 0;
!         long [] returnArray = new long[2];
!             
          for (int compId = 0 ; compId < components.length ; compId++) {
              comp = components[compId];
              if (!comp.isVisible()) {
***************
*** 886,892 ****
              preMaximumArrayYIndex = Math.max(curX + curWidth, preMaximumArrayYIndex);
          } //for (components) loop
          // Must specify index++ to allocate well-working arrays.
!         return new Point(preMaximumArrayXIndex, preMaximumArrayYIndex);
      } //PreInitMaximumSizes
  
      /**
--- 887,898 ----
              preMaximumArrayYIndex = Math.max(curX + curWidth, preMaximumArrayYIndex);
          } //for (components) loop
          // Must specify index++ to allocate well-working arrays.
!         /* fix for 4623196.
!          * now return long array instead of Point
!          */
!         returnArray[0] = preMaximumArrayXIndex;
!         returnArray[1] = preMaximumArrayYIndex;
!         return returnArray;
      } //PreInitMaximumSizes
  
      /**
***************
*** 933,942 ****
  
              layoutWidth = layoutHeight = 0; 
              curRow = curCol = -1;
!             Point p = preInitMaximumArraySizes(parent);
!             maximumArrayXIndex = EMPIRICMULTIPLIER*p.x;
!             maximumArrayYIndex = EMPIRICMULTIPLIER*p.y;
  
              xMaxArray = new int[maximumArrayXIndex];
              yMaxArray = new int[maximumArrayYIndex];
  
--- 939,955 ----
  
              layoutWidth = layoutHeight = 0; 
              curRow = curCol = -1;
!             long [] arraySizes = preInitMaximumArraySizes(parent);
  
+             /* fix for 4623196.
+              * If user try to create a very big grid we can
+              * get NegativeArraySizeException because of integer value
+              * overflow (EMPIRICMULTIPLIER*gridSize might be more then Integer.MAX_VALUE).
+              * We need to detect this situation and try to create a
+              * grid with Integer.MAX_VALUE size instead.
+              */
+             maximumArrayXIndex = (EMPIRICMULTIPLIER * arraySizes[0] > Integer.MAX_VALUE )? Integer.MAX_VALUE : EMPIRICMULTIPLIER*(int)arraySizes[0];
+             maximumArrayYIndex = (EMPIRICMULTIPLIER * arraySizes[1] > Integer.MAX_VALUE )? Integer.MAX_VALUE : EMPIRICMULTIPLIER*(int)arraySizes[1];
              xMaxArray = new int[maximumArrayXIndex];
              yMaxArray = new int[maximumArrayYIndex];

###@###.### 2005-03-14 09:02:49 GMT
                                     
2005-03-14
EVALUATION

Commit to fix in next release (JCK).  
###@###.### 2002-01-14
Waiting to see what happens with this test.  At this point, it fails at least as far back as 1.3.1.
###@###.### 2003-05-08

Still fails with 1.5b19:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 512
      at java.awt.GridBagLayout.GetLayoutInfo(GridBagLayout.java:905)
      at java.awt.GridBagLayout.getLayoutInfo(GridBagLayout.java:821)
      at java.awt.GridBagLayout.preferredLayoutSize(GridBagLayout.java:641)
      at java.awt.Container.preferredSize(Container.java:1544)
      at java.awt.Container.getPreferredSize(Container.java:1530)
      at java.awt.Window.pack(Window.java:457)
      at addLC.main(addLC.java:32)

The failing line is:
      for (i = curX; i < (curX + curWidth); i++) { yMax[i] = py; }
###@###.### 2003-09-15

Fixing 4254022 (PERF: GridBagLayout inefficiency), which has over 30 JDC votes, would also fix this bug in that it wouldn't limit the grid to 512 items.
###@###.### 2003-10-15

After modifying GridBagLayoutInfo to dynamically size its arrays, I run into a java.lang.OutOfMemoryError when running this test.  I also tried setting MAXGRIDSIZE to Integer.MAX_VALUE.  This immediately fails with:

/net/awt-blade/localhome/bchristi/tiger/build/solaris-sparc/bin/java -Xmx3930M addLC
Exception in thread "main" java.lang.OutOfMemoryError: Requested array size exceeds VM limit

I conclude that even if we fix the ArrayIndexOutOfBoundsException, there is no way this test can pass due to memory constraints.  Perhaps we need to change the spec to reflect this.
###@###.### 2003-10-17

I got word back from the JCK lead in SPB.  It "is not API 
javadoc responsibility to cover this", so I'm only going to change the doc to state that we no longer use MAXGRIDSIZE.  See 4254022.
###@###.### 2003-10-22

Initially this bug filed against AIOOBE inside GridBagLayout.
After some fixes in this layout manager we become able to create
large grids (bigger then 512 cells). When user tries to create
Integer.MAX_VALUE grid he could get integer value overflow and an
attempt to create an array with negative size. 

###@###.### 2005-03-11 17:28:56 GMT
                                     
2005-03-11
CONVERTED DATA

BugTraq+ Release Management Values

COMMIT TO FIX:
mustang


                                     
2004-09-07



Hardware and Software, Engineered to Work Together