Bug 482990 - Load time weaving silently generates invalid classes without StackMapTables if aj.org.objectweb.asm package is not found
Summary: Load time weaving silently generates invalid classes without StackMapTables i...
Status: RESOLVED FIXED
Alias: None
Product: AspectJ
Classification: Tools
Component: LTWeaving (show other bugs)
Version: 1.8.7   Edit
Hardware: PC All
: P3 normal (vote)
Target Milestone: 1.8.8   Edit
Assignee: aspectj inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-11-25 05:22 EST by Davy Herben CLA
Modified: 2015-11-25 15:28 EST (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Davy Herben CLA 2015-11-25 05:22:57 EST
After upgrading from AspectJ 1.7.2 (Spring EBR osgi bundle) to 1.8.7 (Apache ServiceMix osgi bundle) in our OSGI environment, we started seeing VerifyErrors like these for load-time woven classes:

HttpServiceContext{httpContext=our.paclage.BundleHttpContext@5552fc77}: java.lang.VerifyError: Expecting a stackmap frame at branch target 63|Exception Details:|  Location:|    our/package/OurResource.<init>()V @23: ifnull|  Reason:|    Expected stackmap frame at this location.|  Bytecode:|    0x0000000: 2ab7 0001 b200 c62a 2ab8 009c 4db2 0096|    0x0000010: 2a2a b800 9c4c 2ac6 0028 2ab6 00ac 12ae|    0x0000020: b600 bc99 001c 2ab6 00ac 12ae b600 b4c0|    0x0000030: 00ae b800 b899 000a b800 a22a b600 a800|    0x0000040: 2ac6 0021 2ab6 00ac 12ae b600 bc99 0015|    0x0000050: 2ab6 00ac 12ae b600 b4c0 00ae b800 b89a|    0x0000060: 0021 2ac6 001d 2ab6 00ac 12ae b600 bc99|    0x0000070: 0011 2bb8 00c3 9900 0ab8 00a2 2ab6 00bf|    0x0000080: 00a7 0003 2ab6 00ac 12ae b600 b4c0 00ae|    0x0000090: b800 b89a 0011 2cb8 00c3 9900 0ab8 00a2|    0x00000a0: 2ab6 00bf b1                           |
java.lang.VerifyError: Expecting a stackmap frame at branch target 63|Exception Details:|  Location:|    our/package/OurResource.<init>()V @23: ifnull|  Reason:|    Expected stackmap frame at this location.|  Bytecode:|    0x0000000: 2ab7 0001 b200 c62a 2ab8 009c 4db2 0096|    0x0000010: 2a2a b800 9c4c 2ac6 0028 2ab6 00ac 12ae|    0x0000020: b600 bc99 001c 2ab6 00ac 12ae b600 b4c0|    0x0000030: 00ae b800 b899 000a b800 a22a b600 a800|    0x0000040: 2ac6 0021 2ab6 00ac 12ae b600 bc99 0015|    0x0000050: 2ab6 00ac 12ae b600 b4c0 00ae b800 b89a|    0x0000060: 0021 2ac6 001d 2ab6 00ac 12ae b600 bc99|    0x0000070: 0011 2bb8 00c3 9900 0ab8 00a2 2ab6 00bf|    0x0000080: 00a7 0003 2ab6 00ac 12ae b600 b4c0 00ae|    0x0000090: b800 b89a 0011 2cb8 00c3 9900 0ab8 00a2|    0x00000a0: 2ab6 00bf b1                           |
	at java.lang.Class.getDeclaredConstructors0(Native Method)
...


Investigation of the woven bytecode in _ajdump revealed that the woven classes were indeed missing their StackMapTables. After much searching, we found out that the root cause was the fact that the ServiceMix bundle did not include the renamed ASM library (aj.org.objectweb.asm.* packages). We logged a bug for this here:

https://issues.apache.org/jira/browse/SM-2744

It took us a long time to find this, because instead of throwing an Exception (ClassNotFoundException or similar), AspectJ simply decides to not generate StackMapTables, thus generating bytecode that is completely invalid for Java 1.7 or higher.

The relevant code snippets:

org.aspectj.weaver.bcel.LazyClassGen:

if (((myGen.getMajor() == Constants.MAJOR_1_6 && world.shouldGenerateStackMaps()) || myGen.getMajor() > Constants.MAJOR_1_6) && AsmDetector.isAsmAround) {
    wovenClassFileData = StackMapAdder.addStackMaps(world, wovenClassFileData);
}

org.aspectj.weaver.bcel.asm.AsmDetector:

public class AsmDetector {

	public static boolean isAsmAround;

	static {
		try {
			Class<?> reader = Class.forName("aj.org.objectweb.asm.ClassReader");
			Class<?> visitor = Class.forName("aj.org.objectweb.asm.ClassVisitor");
			Method m = reader.getMethod("accept", new Class[] { visitor, Integer.TYPE });
			isAsmAround = m != null;
		} catch (Exception e) {
			isAsmAround = false;
		}
		// System.out.println(isAsmAround?"ASM detected":"No ASM found");
	}
}

As far as I can see, The LazyClassGen class should throw an Exception if myGen.getMajor() > Constants.MAJOR_1_6 && !AsmDetector.isAsmAround 

Also, I think AsmDetector could be more lenient and also accept a regular (non-included) ASM. If I've seen correctly, the aj-prefixed inlined version is simply a renamed copy of ASM 5.0.4, so using the regular ASM should work. I'm also not sure why this ASM needs to be renamed and embedded in the first place, but there is probably a reason that I'm not aware of.
Comment 1 Andrew Clement CLA 2015-11-25 11:53:59 EST
I agree the error reporting should be better there. That code hasn't been touched for a long time and 1.7 or greater is now the norm rather than the unusual case.  However, i'm leaning to keeping the embedded asm - it is very small and depending on whatever we find in the environment may not discover a version that is compatible. This version has been through all the AspectJ tests to verify it does the right thing. For error reports that come in I know what everyone must be running.
Comment 2 Andrew Clement CLA 2015-11-25 15:19:52 EST
Exception will now be thrown if asm is missing.
Comment 3 Davy Herben CLA 2015-11-25 15:28:24 EST
Thanks for that quick reaction, that commit looks like it should fix it, I'll check tomorrow. Hopefully the ServiceMix guys will also change their bundle, but for now our problem is solved by inlining the aj.org.objectweb.asm packages in our own osgi bundle. Finding out what was wrong was most of the battle, and your commit will make that much easier for others.

Any idea on when you'll be releasing 1.8.8?