Bug 114855 - [compiler] OutOfMemoryError compiling deeply nested try-catch
Summary: [compiler] OutOfMemoryError compiling deeply nested try-catch
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.1   Edit
Hardware: PC Windows 2000
: P3 normal (vote)
Target Milestone: 3.1.2   Edit
Assignee: Olivier Thomann CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-11-02 18:15 EST by Art Dyer CLA
Modified: 2006-01-10 05:25 EST (History)
0 users

See Also:


Attachments
Proposed fix (3.20 KB, patch)
2005-11-02 22:43 EST, Olivier Thomann CLA
no flags Details | Diff
Variation on the patch which isn't performing any sorting (2.83 KB, patch)
2005-11-03 04:13 EST, Philipe Mulet CLA
no flags Details | Diff
New proposal (4.53 KB, patch)
2005-11-03 09:32 EST, Olivier Thomann CLA
no flags Details | Diff
New proposal (4.55 KB, patch)
2005-11-03 10:18 EST, Olivier Thomann CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Art Dyer CLA 2005-11-02 18:15:23 EST
An OutOfMemoryError occurs when compiling a class with deeply-nested try-catch 
blocks.

This is probably best reproduced using the batch compiler from the command 
line.  You can import the class below into a Java project if you wish, but if 
you do, you should expect to be stuck at "Building workspace: (1%)" for a 
while, with the CPU pegged, and eventually having to shut down your workbench.

I ran the compiler thus:

java -classpath c:/eclipse/plugins/org.eclipse.jdt.core_3.1.0.jar 
org.eclipse.jdt.internal.compiler.batch.Main ExcNested.java 

Trying to compile the class with the batch compiler results in:

  Internal compiler error
  java.lang.OutOfMemoryError: Java heap space

Upping the heap to -Xmx400m doesn't help, but it does take longer to fail.

I tried this with both 1.4 & 1.5 VMs and with both 3.0.2 and 3.1.0 versions of 
jdtcore.

Javac 1.4 & 1.5 and Jikes 1.21 compile this with no trouble.

/* This program is derived from test.OSF.valid.lang.ExcNested, which bears the
 * following notices:
 *
 * Copyright (c) 1995, 1996
 * Open Software Foundation, Inc.
 *
 * OSF DISCLAIMS ALL WARRANTIES, WHETHER EXPRESS OR IMPLIED,
 * WITH RESPECT TO THIS SOFTWARE INCLUDING, WITHOUT LIMITATION,
 * ANY WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
 * PARTICULAR PURPOSE.  IN NO EVENT SHALL OSF BE LIABLE FOR ANY
 * SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN CONTRACT, TORT
 * INCLUDING NEGLIGENCE, OR OTHER LEGAL THEORY ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 */

/*
 * This file is part of an OSF RI software distribution. This software is
 * distributed under the terms of a free license for non-commercial use.
 *
 * You should have received a copy of those terms along with this file.
 * Please see file COPYRIGHT.
 *
 * If not, please write to: OSF RI, 2 Av. de Vignate, 38610 Gieres, France
 */

public class ExcNested
{
  public ExcNested() {}

  static int except_count;

  static boolean test_result = true;
  
  static Throwable all_except[] =
  {
    new AbstractMethodError(),             //  0
    new ArithmeticException(),             //  1
    new ArrayIndexOutOfBoundsException(),  //  2
    new ArrayStoreException(),             //  3
    new ClassCastException(),              //  4
    new ClassCircularityError(),           //  5
    new ClassFormatError(),                //  6
    new ClassNotFoundException(),          //  7
    new CloneNotSupportedException(),      //  8
    new Error(),                           //  9
    new Exception(),                       // 10
    new IllegalAccessError(),              // 11
    new IllegalAccessException(),          // 12
    new IllegalArgumentException(),        // 13
    new IllegalMonitorStateException(),    // 14
    new IllegalThreadStateException(),     // 15
    new IncompatibleClassChangeError(),    // 16
    new IndexOutOfBoundsException(),       // 17
    new InstantiationError(),              // 18
    new InstantiationException(),          // 19
    new InternalError(),                   // 20
    new InterruptedException(),            // 21
    new LinkageError(),                    // 22
    new NegativeArraySizeException(),      // 23
    new NoClassDefFoundError(),            // 24
    new NoSuchFieldError(),                // 25
    new NoSuchMethodError(),               // 26
    new NoSuchMethodException(),           // 27
    new NullPointerException(),            // 28
    new NumberFormatException(),           // 29
    new OutOfMemoryError(),                // 30
    new StackOverflowError(),              // 31
    new RuntimeException(),                // 32
    new SecurityException(),               // 33
    new StringIndexOutOfBoundsException(), // 34
    new ThreadDeath(),                     // 35
    new UnknownError(),                    // 36
    new UnsatisfiedLinkError(),            // 37
    new VerifyError(),                     // 38
  };

  private static void check_except(int i)
    throws Throwable
  {
    if (except_count != i)
    {
      System.out.println("Error "+except_count+" != "+i+";");
      test_result=false;
    }
    throw all_except[++except_count];
  }

  public static void main(String[] args) throws Throwable
  {
    try {
      except_count = 0;
      throw all_except[except_count];
    } catch (AbstractMethodError e0) {
      try {
        check_except(0);
      } catch (ArithmeticException e1) {
        try {
          check_except(1);
        } catch (ArrayIndexOutOfBoundsException e2) {
          try {
            check_except(2);
          } catch (ArrayStoreException e3) {
            try {
              check_except(3);
            } catch (ClassCastException e4) {
              try {
                check_except(4);
              } catch (ClassCircularityError e5) {
                try {
                  check_except(5);
                } catch (ClassFormatError e6) {
                  try {
                    check_except(6);
                  } catch (ClassNotFoundException e7) {
                    try {
                      check_except(7);
                    } catch (CloneNotSupportedException e8) {
                      try {
                        check_except(8);
                      } catch (Error e9) {
                        try {
                          check_except(9);
                        } catch (Exception e10) {
                          try {
                            check_except(10);
                          } catch (IllegalAccessError e11) {
                            try {
                              check_except(11);
                            } catch (IllegalAccessException e12) {
                              try {
                                check_except(12);
                              } catch (IllegalArgumentException e13) {
                                try {
                                  check_except(13);
                                } catch (IllegalMonitorStateException e14) {
                                  try {
                                    check_except(14);
                                  } catch (IllegalThreadStateException e15) {
                                    try {
                                      check_except(15);
                                    } catch (IncompatibleClassChangeError e16) {
                                      try {
                                        check_except(16);
                                      } catch (IndexOutOfBoundsException e17) {
                                        try {
                                          check_except(17);
                                        } catch (InstantiationError e18) {
                                          try {
                                            check_except(18);
                                          } catch (InstantiationException e19) {
                                            try {
                                              check_except(19);
                                            } catch (InternalError e20) {
                                              try {
                                                check_except(20);
                                              } catch (InterruptedException 
e21) {
                                                try {
                                                  check_except(21);
                                                } catch (LinkageError e22) {
                                                  try {
                                                    check_except(22);
                                                  } catch 
(NegativeArraySizeException e23) {
                                                    try {
                                                      check_except(23);
                                                    } catch 
(NoClassDefFoundError e24) {
                                                      try {
                                                        check_except(24);
                                                      } catch (NoSuchFieldError 
e25) {
                                                        try {
                                                          check_except(25);
                                                        } catch 
(NoSuchMethodError e26) {
                                                          try {
                                                            check_except(26);
                                                          } catch 
(NoSuchMethodException e27) {
                                                            try {
                                                              check_except(27);
                                                            } catch 
(NullPointerException e28) {
                                                              try {
                                                                check_except
(28);
                                                              } catch 
(NumberFormatException e29) {
                                                                try {
                                                                  check_except
(29);
                                                                } catch 
(OutOfMemoryError e30) {
                                                                  try {
                                                                    check_except
(30);
                                                                  } catch 
(StackOverflowError e31) {
                                                                    try {
                                                                      
check_except(31);
                                                                    } catch 
(RuntimeException e32) {
                                                                      try {
                                                                        
check_except(32);
                                                                      } catch 
(SecurityException e33) {
                                                                        try {
                                                                          
check_except(33);
                                                                        } catch 
(StringIndexOutOfBoundsException e34) {
                                                                          try {
                                                                            
check_except(34);
                                                                          } 
catch (ThreadDeath e35) {
                                                                            try 
{
                                                                              
check_except(35);
                                                                            } 
catch (UnknownError e36) {
                                                                              
try {
                                                                                
check_except(36);
                                                                              } 
catch (UnsatisfiedLinkError e37) {
                                                                                
try {
                                                                                
  check_except(37);
                                                                                
} catch (VerifyError e38) {
                                                                                
  ++except_count;
                                                                                
}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
    // Check that all exceptions have been raised.
    System.out.println(test_result & (except_count == all_except.length));
  }
}
Comment 1 Olivier Thomann CLA 2005-11-02 19:52:45 EST
The problem comes from the code generation.
I am investigating.
Comment 2 Olivier Thomann CLA 2005-11-02 20:02:25 EST
The problem comes from the forward reference count inside the labels.
Comment 3 Olivier Thomann CLA 2005-11-02 22:43:47 EST
Created attachment 29248 [details]
Proposed fix
Comment 4 Philipe Mulet CLA 2005-11-03 04:09:49 EST
In practice, forward refs are generally sorted already (per construction). Thus
I suspect Arrays.sort(int[],...) is not optimized for this scenario. 
Also note that individual additions of forward refs is not checking for
duplicates (only checked when adding all refs from other label).

Once fixed, should be backported to 3.1, and likely to 3.0.
Comment 5 Philipe Mulet CLA 2005-11-03 04:13:08 EST
Created attachment 29255 [details]
Variation on the patch which isn't performing any sorting

It does check for dup addition of single forward refs. If array size remains
small , the non sorting may not be an issue.
Comment 6 Olivier Thomann CLA 2005-11-03 09:32:55 EST
Created attachment 29265 [details]
New proposal
Comment 7 Olivier Thomann CLA 2005-11-03 10:18:35 EST
Created attachment 29267 [details]
New proposal

This will be released as soon as M3 is declared.
Comment 8 Olivier Thomann CLA 2005-11-03 11:54:21 EST
Backported to 3.1 maintenance stream.
Added regression test
org.eclipse.jdt.core.tests.compiler.regression.TryStatementTest.test031
Comment 9 Olivier Thomann CLA 2005-11-03 12:21:36 EST
Backported to 3.0 maintenance stream.
Added regression test
org.eclipse.jdt.core.tests.compiler.regression.TryStatementTest.test026
Comment 10 Olivier Thomann CLA 2005-11-04 10:20:38 EST
Fixed and released in HEAD.
Added regression test
org.eclipse.jdt.core.tests.compiler.regression.TryStatementTest.test032
Comment 11 Frederic Fusier CLA 2005-12-12 10:51:40 EST
Verified for 3.2 M4 using build I20051212-0010
Comment 12 Frederic Fusier CLA 2006-01-09 06:47:32 EST
Reopen for 3.1.2 verification
Comment 13 Frederic Fusier CLA 2006-01-09 06:47:45 EST
We also need to verify that's this bug fix is in R3_1_maintenance stream as
well before 3.1.2 delivery...
Comment 14 Maxime Daniel CLA 2006-01-10 04:52:53 EST
Verified for 3.1.2 using build M20060109-1200.
Comment 15 Frederic Fusier CLA 2006-01-10 05:25:05 EST
Verified for 3.1.2 using build M20060109-1200 (maxime)