Bug 145397 - [1.6][compiler] Invalid StackMap attribute
Summary: [1.6][compiler] Invalid StackMap attribute
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.2   Edit
Hardware: All All
: P3 normal (vote)
Target Milestone: 3.2.1   Edit
Assignee: Olivier Thomann CLA
QA Contact:
URL:
Whiteboard:
Keywords:
: 154480 (view as bug list)
Depends on:
Blocks:
 
Reported: 2006-06-05 14:00 EDT by Doug Simon CLA
Modified: 2006-09-19 01:05 EDT (History)
2 users (show)

See Also:


Attachments
Java source that is incorrectly compiled by Eclipse (1.78 KB, text/plain)
2006-06-05 14:02 EDT, Doug Simon CLA
no flags Details
Proposed fix (5.41 KB, patch)
2006-06-06 17:39 EDT, Olivier Thomann CLA
no flags Details | Diff
Better patch (52.90 KB, patch)
2006-06-26 15:57 EDT, Olivier Thomann CLA
no flags Details | Diff
Proposed patch (71.21 KB, patch)
2006-08-23 11:27 EDT, Olivier Thomann CLA
no flags Details | Diff
Regression tests updated (65.98 KB, patch)
2006-08-23 11:27 EDT, 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 Doug Simon CLA 2006-06-05 14:00:17 EDT
I have a Java source file (attached in next post) that when compiled by Eclipse, produces a class file that causes javap from JDK 1.6.0-beta2-b86 to crash when trying to disassemble a particular StackMap attribute. I am using Eclipse with build ID I20060526-0010 on a Linux-AMD64 platform.
Comment 1 Doug Simon CLA 2006-06-05 14:02:44 EDT
Created attachment 43501 [details]
Java source that is incorrectly compiled by Eclipse

The StackMap attribute generated for the 'getExceptionDispatchers' method causes javap in the latest Mustang (i.e. JDK 6) build to crash.
Comment 2 Olivier Thomann CLA 2006-06-05 19:59:27 EDT
I'll investigate.
Comment 3 Olivier Thomann CLA 2006-06-06 16:33:16 EDT
Philippe,

The error reported by javap is fixed by using RC7. However there is another bug.
We don't manage the locals right in the foreach statement. The range for the local corresponding to the elementVariable is too wide.

Here is a shorted example:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

class B {}
class C {}

public class X {

    private List<B> list;

    public ArrayList<B> foo() {
        final ArrayList<B> tab = new ArrayList<B>(list.size());
        for (B b : list) {
            tab.add(b);
        }
        return tab;
    }
    
    public static void main(String[] args) {
    }
}

for (B b : list) {
    tab.add(b);
}
is macro expanded to:
for (Iterator<B> iterator = list.iterator(); iterator.hasNext(); ) {
 	B b = iterator.next();
  	tab.add(b);
}

    0  new java.util.ArrayList [21]
     3  dup
     4  aload_0 [this]
     5  getfield X.list : java.util.List [23]
     8  invokeinterface java.util.List.size() : int [25] [nargs: 1]
    13  invokespecial java.util.ArrayList(int) [31]
    16  astore_1 [tab]
    17  aload_0 [this]
    18  getfield X.list : java.util.List [23]
    21  invokeinterface java.util.List.iterator() : java.util.Iterator [34] [nargs: 1]
    26  astore_3
    27  goto 46
    30  aload_3
    31  invokeinterface java.util.Iterator.next() : java.lang.Object [38] [nargs: 1]
    36  checkcast B [44]
    39  astore_2 [b]
    40  aload_1 [tab]
    41  aload_2 [b]
    42  invokevirtual java.util.ArrayList.add(java.lang.Object) : boolean [46]
    45  pop
    46  aload_3
    47  invokeinterface java.util.Iterator.hasNext() : boolean [50] [nargs: 1]
    52  ifne 30
    55  aload_1 [tab]
    56  areturn

      Line numbers:
        [pc: 0, line: 12]
        [pc: 17, line: 13]
        [pc: 40, line: 14]
        [pc: 46, line: 13]
        [pc: 55, line: 16]
      Local variable table:
        [pc: 0, pc: 57] local: this index: 0 type: X
        [pc: 17, pc: 57] local: tab index: 1 type: java.util.ArrayList
        [pc: 40, pc: 55] local: b index: 2 type: B
      Local variable type table:
        [pc: 17, pc: 57] local: tab index: 1 type: java.util.ArrayList<B>
      Stack map table: number of frames 2
        [pc: 30, full, stack: {}, locals: {X, java.util.ArrayList, _, java.util.Iterator}]
        [pc: 46, full, stack: {}, locals: {X, java.util.ArrayList, B, java.util.Iterator}]

But if you look at the bytecode that we generate, you will see that b is visible when we check iterator.hasNext() and this should not be the case. So I ended up with inconsistent stack frame.

If you use this command line:
java -XX:-FailOverToOldVerifier -Xverify:all X, you'll get a verify error:
Exception in thread "main" java.lang.VerifyError: Inconsistent stackmap frames at branch target 46 in method X.foo()Ljava/util/ArrayList; at offset 27

This is due to the fact that in 27, the locals array looks like:
this ArrayList _ Iterator

And in 46, it looks like:
this ArrayList B Iterator

These two arrays should be identical.

We have a scope for the forearch statement. All variables belongs to this scope, and I believe this is wrong. The elementVariable should not belongs to the same scope that the inits. It should belong to the scope of the action block. So we might want to emulate this by adding a new scope to hold this local that would be a subscope of the foreach scope.

Then b would be put in local 3 instead of 2 and the iterator local would be 2 instead of 3. We could then remove b from the scope and let iterator visible till the end of the condition.

What do you think? I'll start to fix it that way. Let me know if you see anything wrong with this approach.
Comment 4 Olivier Thomann CLA 2006-06-06 17:39:14 EDT
Created attachment 43656 [details]
Proposed fix

This patch removes the elementVariable from the visible locals without introducing a new scope. I'll continue to check if this is good enough to fix this issue.
At least the reported test case would be fixed.
Comment 5 Philipe Mulet CLA 2006-06-07 05:30:39 EDT
Don't we have the same issue with regular for statements as well ?
Adding an extra scope feels overkill, since per construction variables are not inserted in scopes at place they would interfere (i.e. though in scope of inits, inits cannot bind to variable by the time it is resolved).

One thing to double check though, which could vote in favor of inserting a scope, is whether the current solution using one scope is altering the local variable allocation (when computing the variable offset and reusing entries in between sibling scopes). If we can produce a testcase where our allocation is unoptimal, then I would sign up for an extra scope, if not then I would favour an alternate solution.

BTW - is this 3.2.1 or 3.3 ?
Comment 6 Philipe Mulet CLA 2006-06-07 05:48:24 EDT
Cannot reproduce issue with standard FOR loops, as explicit variables are correctly managed (using inits). I suspect a similar story should be put in place for artificially inserted variables (synthetics), since their life cycle doesn't match the entire scope. Added new scopes for these is a no go I think.
Comment 7 Olivier Thomann CLA 2006-06-26 15:57:09 EDT
Created attachment 45323 [details]
Better patch

More complete fix. There is still one remaining issues with try/catch/finally statement.
Comment 8 Olivier Thomann CLA 2006-08-23 10:47:46 EDT
*** Bug 154480 has been marked as a duplicate of this bug. ***
Comment 9 Olivier Thomann CLA 2006-08-23 11:23:51 EDT
Fixed and released in HEAD.
Added org.eclipse.jdt.core.tests.compiler.regression.StackMapAttributeTest.test018/019.
Comment 10 Olivier Thomann CLA 2006-08-23 11:27:00 EDT
Created attachment 48472 [details]
Proposed patch

Final patch that has been released.
Comment 11 Olivier Thomann CLA 2006-08-23 11:27:29 EDT
Created attachment 48473 [details]
Regression tests updated

Corresponding regression tests that have been released.
Comment 12 Olivier Thomann CLA 2006-08-23 11:28:10 EDT
Released for 3.2.1
Comment 13 David Audel CLA 2006-09-12 06:25:22 EDT
Verified for 3.2.1 using build M20060908-1655
Comment 14 Frederic Fusier CLA 2006-09-17 12:19:43 EDT
Released for 3.3 M2
Comment 15 Maxime Daniel CLA 2006-09-19 01:05:04 EDT
Verified for 3.3 M2 using build I20060918-0010.