Community
Participate
Working Groups
When weaving a precompiled JSP, get a runtime VerifyError - "register xxx contains wrong type." The woven byte code decompiles incorrectly. This appears to be like bug #72528.
Created attachment 23753 [details] JSP generated .java file
Created attachment 23754 [details] woven class file
Created attachment 23755 [details] Aspect being woven
Created attachment 23756 [details] Stack trace.
investigate in M4
has to be investigated before 1.5.0 RC1
Helen looked into this one Adrian ... and made some useful observations about the code. I'll get her to append.
Googling on the verify error I found that when someone saw the following error: [java] java.lang.VerifyError: (class: com/athico/rp/entityDefinitions/Address, method: setNumber signature: (I)V) Register 1 contains wrong type it was because in the bytecode they should have had ILOAD, not ALOAD as it was an integer not a reference. ALOAD = load a reference from a local variable ILOAD = load an int from a local variable. I also tried to write a testcase which would produce bytecode similar to the appended class file. What I found was that there is around advice on a method, in this case the around advice affects execution(public void *._jspService(..)). Then, within the execution of _jspService(..) there are calls to "write(..)" which are affected by other around advice. I'll attach a zip of the classes I created. Unfortunately, although the byte code was similar, I couldn't reproduce the verify error. To reproduce I tried the following scenarios (all on the command line): * compile the 3 classes with javac * create a jar with these 3 class files in it * weave the aspect with the jar file * run the output (I added a main method to left_jsp.java) I did this both with java 1.4 and java 5, and with an aspectj 1.2.1 and the latest development build. In all cases I couldn't reproduce it. I also did a quick look through the bytecode of the supplied class file and couldn't see anything which struck me that was an ALOAD which should have been an ILOAD.
Created attachment 30877 [details] zip containing classes which attempt to recreate the problem As mentioned in my above comment, this is a zip of the classes and aspect I created to try to recreate the problem.
I've been looking into this one too today (on the train). Bit of a needle in a haystack, but there were some clues lurking. We know it's a problem with the contents of register 195, and we know it's in the jspService method. If you look at uses of that register within the method, there are a few bunched together that look ok, and then later on out of the blue you see: iinc 195,1 when none of the surrounding code is referencing that register. The other clue is that this is a generated method with a very big body - necessitating the need for wide instructions. Furthermore, we suspect here the classic situation whereby the addition of advice instructions pushes instructions further down the method body over the single-byte barrier. So here's the fragment of suspicious bytecode: 6778: aload_w 515 6782: invokevirtual #230; // MenuDO.getItems:()Ljava/util/Set; 6785: invokeinterface #231, 1; // java/util/Set.size:()I 6790: istore_w 451 6794: aload_w 437 6798: aload_w 515 6802: invokevirtual #239; // MenuDO.getId:()Ljava/lang/Integer; 6805: invokevirtual #246; //ArrayList.add:(Ljava/lang/Object;)Z 6808: pop 6809: new #9; //class java/lang/Integer 6812: dup 6813: aload_0 6814: getfield #14; //Field menuItemSpacing:I ==> 6817: iinc 195, 1 6820: iload_w 451 6824: imul 6825: aload_0 6826: getfield #15; //Field menuExpandedHeight:I 6829: iadd 6830: invokespecial #10; //Method java/lang/Integer."<init>":(I)V with the offending instruction highlighted. Observe the magic formula: 195 + 256 = 451! so we tried to iinc 451, but instead of using a wide instruction, used a normal instruction thus dropping the high bit and giving iinc 195. This bytecode comes from the source code fragment: itemCount = menuForSize.getItems().size(); idList.add(menuForSize.getId()); // calculate the height of the menu Integer height = new Integer(menuItemSpacing * ++itemCount + menuExpandedHeight); heightList.add(height); it's the "++itemCount" that's causing the problem. So the diagnosis is.... the original compiled code had an iinc xxx,1 instruction. We wove into the method body, and on rewriting failed to correctly generate and iinc_w instruction and instead generated an iinc instruction. I suspect this is a bug in BCEL (last time I ran into something similar that's where the problem was). Next step is to try and recreate locally. A program containing a method of the form: public void foo() { int i1 = 1; int i2 = ++i1; int i3 = ++i2; .... int i256 = ++i255; } and then compiled with the -preserveAllLocals flag should do it. We can then weave that method and try to run the result - if my analysis is correct this will produce the same verify error. Then it's a simple matter of tracking into BCEL and watching the IINC instruction get updated and written out. Helen: I'm at a meeting in London again all day tomorrow - could you please try generating a class like the above and testing out my hypothesis? Thanks, Adrian.
One last clue for a hopeful fix tomorrow: A quick look at IINC in BCEL (org.aspectj.apache.bcel.generic.IINC) reveals what looks to be a likely source of the bug. IINC has it's own calculation of wide, but the superclass LocalVariableInstruction has a separate (private final) method that tests for wideness based on a different criteria. When writing the bytes out, it is the superclass's test for wide that is used rather than the IINC one. Doesn't look right to me on a first glance. Andy / Helen - reckon this might be enough to go on for you to put in a fix for this tomorrow for me?
yes - sounds the likely problem - fix should be no probs. Good detective work ;)
one last thought.... the test program I suggested probably won't recreate the verify error (though examining the generated bytecode would still show the flaw) - since all the vars are ints. Try making the earlier vars Objects, and then put an int var with a ++ instruction on the end of the list....
Created attachment 30933 [details] class which recreates the verify error with aspectj 1.2.1 Compiling the attached class using "ajc -preserveAllLocals C2.java", then weaving the generate classfile with the following aspect: public aspect A { pointcut p() : execution(public void C2.foo(..)); void around() : p() { proceed(); } } I found the following: - with aspectj version 1.2.1 (which is what this bug was raised with) I recreated the verify error when running the class and the generated output is as Adrian describes: 1627: aload_1 1628: invokeinterface #44, 1; //InterfaceMethod java/util/List.size:()I 1633: istore_w 387 1637: new #46; //class java/lang/Integer 1640: dup 1641: aload_0 1642: getfield #14; //Field menuItemSpacing:I 1645: iinc 131, 1 <=== incorrect 1648: iload_w 387 1652: imul 1653: aload_0 1654: getfield #16; //Field menuExpandedHeight:I 1657: iadd 1658: invokespecial #49; //Method java/lang/Integer."<init>":(I)V - with aspectj version 1.5.0M5 I'm unable to recreate the verify error and the generated output is as expected: 1819: aload_1 1820: invokeinterface #44, 1; //InterfaceMethod java/util/List.size:()I 1825: istore_w 387 1829: new #46; //class java/lang/Integer 1832: dup 1833: aload_0 1834: getfield #14; //Field menuItemSpacing:I 1837: iinc_w 387, 1 <=== as expected 1843: iload_w 387 1847: imul 1848: aload_0 1849: getfield #16; //Field menuExpandedHeight:I 1852: iadd 1853: invokespecial #49; //Method java/lang/Integer."<init>":(I)V Looking at the resource history for IINC.java, it looks like this was fixed as part of bug 106130.
As we discovered (finally...) this is already fixed in AspectJ5 ... *** This bug has been marked as a duplicate of 106130 ***