Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 366999

Summary: VerifyError: Inconsistent stackmap frames
Product: [Eclipse Project] JDT Reporter: kurt <kurt2002>
Component: CoreAssignee: Srikanth Sankaran <srikanth_sankaran>
Status: RESOLVED FIXED QA Contact:
Severity: normal    
Priority: P3 CC: amj87.iitr, daniel_megert, jarthana, kurt2002, michael.f.obrien, Olivier_Thomann, remy.suen, srikanth_sankaran
Version: 3.8Flags: daniel_megert: pmc_approved+
Target Milestone: 3.6.2+J7   
Hardware: PC   
OS: Linux   
Whiteboard:
Attachments:
Description Flags
Proposed fix + regression test none

Description kurt CLA 2011-12-17 03:58:47 EST
Build Identifier: Version: 3.8.0 Build id: I20111209-1447


java version "1.7.0_04-ea"
Java(TM) SE Runtime Environment (build 1.7.0_04-ea-b04)
Java HotSpot(TM) Server VM (build 23.0-b06, mixed mode)

in case it matters:
I set my default VM-options in eclipse to: -XX:-UseLoopPredicate

if you comment the sysout-line in finally, or have no nested try-resource it works.

source:

package ecerr;

import java.io.BufferedReader;
import java.io.Closeable;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class VerErr {

  static class C
      implements Closeable {
    @Override
    public void close() throws IOException {
      //
    }
  }

  int run() throws IOException {
    int lcnt = 0;
    try (C c = new C();) {
      try (final BufferedReader br =
          new BufferedReader(new FileReader(new File("logging.properties")))) {
        String s;
        while ((s = br.readLine()) != null)
          lcnt++;
        return lcnt;
      }
    } finally {
      System.out.println("read " + lcnt + " lines");
    }
  }

  public static void main(final String[] args) throws IOException {
    new VerErr().run();
  }
}


Reproducible: Always

Steps to Reproduce:
1. compile and run the given class in eclipse-ide
Comment 1 kurt CLA 2011-12-17 04:01:21 EST
sorry forgot: it also works with return-type void of run-method
Comment 2 kurt CLA 2011-12-17 04:04:49 EST
looks like I'm not awake today - here is my stacktrace:

Exception in thread "main" java.lang.VerifyError: Inconsistent stackmap frames at branch target 86 in method ecerr.VerErr.run()I at offset 78
	at java.lang.Class.getDeclaredMethods0(Native Method)
	at java.lang.Class.privateGetDeclaredMethods(Class.java:2442)
	at java.lang.Class.getMethod0(Class.java:2685)
	at java.lang.Class.getMethod(Class.java:1620)
	at sun.launcher.LauncherHelper.getMainMethod(LauncherHelper.java:488)
	at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:480)
Comment 3 Ayushman Jain CLA 2011-12-19 00:49:51 EST
A possible workaround until this bug is fixed. Use -XX:-UseSplitVerifier
Comment 4 Olivier Thomann CLA 2011-12-22 11:07:11 EST
In this case, the problem comes from the initialization range of the secret return value variable. It is not properly added after the value is stored. I'll propose a patch shortly.
Comment 5 Olivier Thomann CLA 2011-12-22 11:14:27 EST
I am running tests. If successful, I will post the patch.
Comment 6 Olivier Thomann CLA 2011-12-22 13:54:39 EST
Created attachment 208747 [details]
Proposed fix + regression test

All tests are green. More testing might be required though. Srikanth, I let you review it. It makes sense for me to "expose" the local as soon as it is stored. The initialization range looks better with the fix (you need to hack the code to expose synthetic locals).
Comment 7 Olivier Thomann CLA 2011-12-22 13:55:50 EST
If ok, this will need to be backported to 3.7.2 and 3.6.2+ with Java 7.
Comment 8 Srikanth Sankaran CLA 2012-01-03 06:58:07 EST
(In reply to comment #6)

> All tests are green. More testing might be required though. Srikanth, I let you
> review it. It makes sense for me to "expose" the local as soon as it is stored.
> The initialization range looks better with the fix (you need to hack the code
> to expose synthetic locals).

Thanks for the patch Olivier. I agree with the change and the patch
looks good. 

I am still puzzled as to why this would show up only now with TWR. Will
continue to experiment.
Comment 9 Srikanth Sankaran CLA 2012-01-03 08:24:37 EST
(In reply to comment #8)

> I am still puzzled as to why this would show up only now with TWR. Will
> continue to experiment.

i.e Given the fix has nothing to do with TWR per se, why is it that we are
encountering this problem only now ?  Is it that the problem could be reproduced
with plain try statements but hasn't surfaced so far due to the automatic
fall back used by JDK6 ?
Comment 10 Olivier Thomann CLA 2012-01-03 10:18:40 EST
(In reply to comment #9)
> i.e Given the fix has nothing to do with TWR per se, why is it that we are
> encountering this problem only now ?  Is it that the problem could be
> reproduced
> with plain try statements but hasn't surfaced so far due to the automatic
> fall back used by JDK6 ?
This is also what I think. The problem can only be reproduced if there is a try/catch/finally with a return statement inside the try block that returns a value.
It should not be too difficult to extract a test case that is not related to the TWR.
Comment 11 Srikanth Sankaran CLA 2012-01-03 23:48:39 EST
Smaller test case:

public class X implements AutoCloseable {
    @Override public void close() {
    }
  static int run()  {
    int i = 0;
    try (X x = new X(); X xx = new X()) {
        return i;
    } finally {
    	i = 0;
    }
  }
  public static void main(final String[] args)  {
      run();
  }
}

Problem disappears if finally block is empty, or if there is a single resource.
Comment 12 Srikanth Sankaran CLA 2012-01-04 01:16:16 EST
OK, I know why this problem does not show up with plain try blocks.
As a part of the fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=169017,
we have some code change in org.eclipse.jdt.internal.compiler.ast.TryStatement.generateSubRoutineInvocation(BlockScope, CodeStream, Object, int, LocalVariableBinding) that "pulls up" the
variable range to make it correct (codeStream.addVariable(secretLocal);)
		
The new code generation for resource closures happens to have been coded
ahead of this pull up, thereby messing up the ranges.

However, I do think that the proposed patch does the more appropriate thing
when it comes to ensuring the ranges are correct, i.e exposing them as soon
as they are initialized is the right approach.

It is also consistent with what we do for other scenarios where we manage secret
synthetics (cf ForeachStatement, SwitchStatement, SynchronizedStatement, 
TryStatement etc)
Comment 13 Srikanth Sankaran CLA 2012-01-04 03:52:43 EST
Released fix and tests for 3.8 M5 via http://git.eclipse.org/c/jdt/eclipse.jdt.core.git/commit/?id=cc0019928c0ad43743cfd13562c67921889017a2

This is the same fix as provided by Olivier, but I also went ahead and
deleted the second addVariable method call arising from 
TryStatement.generateSubRoutineInvocation that is referred to in comment#12
Comment 14 Srikanth Sankaran CLA 2012-01-04 03:54:08 EST
Ayush, the commit http://git.eclipse.org/c/jdt/eclipse.jdt.core.git/commit/?id=cc0019928c0ad43743cfd13562c67921889017a2 needs to be back ported too.
Comment 15 Srikanth Sankaran CLA 2012-01-09 10:39:53 EST
Dani, we need this back ported to 3.7.2 and probably to 
3.7.2+java7 also. It is long standing latent bug that is
triggered by new code generated for TWR. Fix is clean.
Comment 16 Dani Megert CLA 2012-01-09 11:51:09 EST
(In reply to comment #15)
> Dani, we need this back ported to 3.7.2 and probably to 
> 3.7.2+java7 also.
You mean 3.6.2+Java7, right?

+1 to backport.
Comment 17 Ayushman Jain CLA 2012-01-10 00:37:35 EST
Released in 3.7 maintenance via commit cb25beb53fbe8773b2156963a511ad0ad5ad6862
Comment 19 Dani Megert CLA 2012-01-10 02:48:18 EST
(In reply to comment #18)
> Released in 3.6.2+Java7 branch via
> http://git.eclipse.org/c/jdt/eclipse.jdt.core.git/commit/?h=R3_6_maintenance_Java7&id=bf6d70c82b170588606e6351c5eee3349eb951a1

Please not that you still need to do the build input manually (as in contrast to 3.7.2), see bug 364676.
Comment 20 Jay Arthanareeswaran CLA 2012-01-19 02:48:12 EST
Verified for 3.7.2 RC2 with build M20120118-0800
Comment 21 Jay Arthanareeswaran CLA 2012-01-23 23:47:21 EST
Verified for 3.8M5 using I20120122-2000
Comment 22 Srikanth Sankaran CLA 2012-02-07 01:11:55 EST
(In reply to comment #3)
> A possible workaround until this bug is fixed. Use -XX:-UseSplitVerifier

For posterity's sakes recording here that this workaround does work
at least as of Sun JVM 7b147. However, it is NOT supposed to work and 
does not with IBM JVM.