Bug 279298 - AspectJ LTW with Cobertura
Summary: AspectJ LTW with Cobertura
Status: RESOLVED FIXED
Alias: None
Product: AspectJ
Classification: Tools
Component: LTWeaving (show other bugs)
Version: 1.6.4   Edit
Hardware: PC Windows XP
: P2 major (vote)
Target Milestone: 1.6.7   Edit
Assignee: aspectj inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2009-06-05 14:02 EDT by Scott Frederick CLA
Modified: 2010-03-17 14:08 EDT (History)
5 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Scott Frederick CLA 2009-06-05 14:02:54 EDT
We are using AspectJ LTW along with Cobertura for code coverage. Class files are
weaved just fine if they are not instrumented with Cobertura, but when
AspectJ attempts to weave the same aspects into Cobertura-instrumented
copies of the same class files, weaving fails with the following error:

>> error at com\mycompany\MyAspect.java::0 Cannot read debug info for
@Aspect to handle formal binding in pointcuts (please compile with 'javac
-g' or '<javac debug='true'.../>' in Ant)

The attached project demonstrates the problem. It contains one simple aspect, a target class, and a unit test for the aspect. To see the problem, run the "unittest" target in the included Ant build file. This will run the single unit test twice. In the first pass, the test is run with javac-generated (i.e. uninstrumented) class files. The aspect is correctly woven and the test passes. In the second pass, the test is run with Cobertura-instrumented class files. There is an error during LTW, and the test fails.
Comment 1 Scott Frederick CLA 2009-06-05 14:10:49 EDT
The example project zip file is too big for bugzilla, I will make it available elsewhere and provide a link.
Comment 2 Scott Frederick CLA 2009-06-05 19:48:02 EDT
The example project is available here: http://github.com/scottfrederick/aspectj-cobertura-example.
Comment 3 Andrew Clement CLA 2009-06-08 13:15:09 EDT
the problem here is that Cobertura has moved the start positions of all the local variable table entries.  Instead of starting at 0 they now start at 6.  AspectJ uses the rule that variables defined from position 0 are the names of the parameters.  

  LocalVariableTable: 
   Start  Length  Slot  Name   Signature
   6      40      0    this       Lcom/example/ExampleAspect;
   6      40      1    pjp       Lorg/aspectj/lang/ProceedingJoinPoint;
   6      40      2    __cobertura__line__number__       I
   6      40      3    __cobertura__branch__number__       I

Cobertura has inserted extra bytecode ahead of the main code, but that doesn't mean that 'this' and 'pjp' should be moved, since they are defined from the very start of the method because they are method arguments.

I'm not sure what I want to do about this right now.

However, the workaround is to define the argument names in the advice annotation - that works.

@Around(value = "monitorDoSomething()",argNames="pjp")
public Object aroundMonitorDoSomething(ProceedingJoinPoint pjp) throws Throwable {
Comment 4 Andrew Clement CLA 2009-06-08 16:08:57 EDT
let me know what you think of that workaround.  It doesn't seem unreasonable for that to be required if the code is going to be modified by a third party.

I can make AspectJ just take the first parameters in the method that make sense for it (skipping 'this' for static contexts) but that does seem a bit fragile since I may just be grabbing local variable names and not parameter names.
Comment 5 Scott Frederick CLA 2009-06-15 17:30:47 EDT
I will also take a look at the Cobertura code and see if I can figure out why they modify the code in the way they do, and if it is possible to change Cobertura. I will let you know what I find out.

Thanks for researching this. 
Comment 6 Jeffrey Bennett CLA 2009-10-14 09:24:59 EDT
FWIW, this bug has also bitten us - using AspectJ 1.6.4 and Cobertura 1.9.3.

Interestingly enough, we were previously using LTW from Aspectwerkz 2.0 with Cobertura, and did not suffer these problems.  We have been stuck on Aspectwerkz for over a year because the LTW in AspectJ did not work properly when previously evaluated.  I know Aspectwerkz project has folded into AspectJ now.  

Does looking at how Aspectwerkz does its LTW (which works with Cobertura) offer any solution that can be used to get AspectJ LTW to also work with Cobertura?
Comment 7 Andrew Clement CLA 2009-10-14 12:03:07 EDT
anything I do is a workaround for what cobertura is doing to the bytecode (see comment 3).  I don't need to see what Aspectwerkz did to understand what to do, AspectJ is being more strict and expecting particular (as produced by compilers) input - the fix would be to cope with unusual input like this, if cobertura isn't going to adjust the output it produces.
Comment 8 Andrew Clement CLA 2009-10-14 12:05:13 EDT
I should add - with this only being hit now and again and not having any votes, I haven't put any time into it.  thanks for letting me know you are also hitting it, I will raise the priority because of that.
Comment 9 statta CLA 2009-10-14 19:09:42 EDT
Andy, I took Scott Frederick's code, replaced the TestNG test case with a Cactus test, performed the changes you suggested and ran it from within the Tomcat container. It failed for the same reason ( [cactus] [WebappClassLoader@165b7e] error at com\example\ExampleAspect.java::O Cannot read debug info for @Aspect to handle formal binding in pointcuts).

Here's the Byte Code

   Local variable table:
        [pc: 6, pc: 21] local: this index: 0 type: com.example.ExampleAspect
        [pc: 6, pc: 21] local: __cobertura__line__number__ index: 1 type: int
        [pc: 6, pc: 21] local: __cobertura__branch__number__ index: 2 type: int

  @org.aspectj.lang.annotation.Around(value="monitorDoSomething()",
    argNames="pjp")
  public java.lang.Object aroundMonitorDoSomething(org.aspectj.lang.ProceedingJoinPoint pjp) throws java.lang.Throwable;

Thoughts???
Comment 10 Andrew Clement CLA 2009-10-15 13:59:12 EDT
I recall that error about missing debug information coming out for the wrong reasons sometimes.  On a quick look I could only find bug 202088 which has been fixed for a while.  

I will try and find some time to work around what cobertura is doing, but it is likely to take me a couple of weeks to get to it.
Comment 11 Andrew Clement CLA 2009-10-23 12:42:53 EDT
I've committed the fix for enabling AspectJ to cope with the quirky bytecode that cobertura creates.  There is no flag to turn on as the function that goes searching for the argument names only kicks in if they aren't found where they are supposed to be.

The fix is in the currently available dev build.
Comment 12 statta CLA 2009-10-23 19:18:50 EDT
Works like charm! Thanks a lot for doing this Andy.

Just a side note for others working on projects involving Cactus, Cobertura and Aspectj - Cobertura serialized file thats used to store the coverage information is getting locked  and I will have to investigate why thats happening (multiple JVMs perhaps).
Comment 13 statta CLA 2010-03-17 14:08:40 EDT
There is one other thing Cobertura is doing in some cases that's causing AspectJ to mishandle the byte code. Developers might find it useful.

Aspect J expects the Byte code's local variable table data to be in the
following order (example code)

Local variable table:
[pc: 6, pc: 21] local: this index: 0 type: com.example.ExampleAspect
[pc: 6, pc: 21] local: __cobertura__line__number__ index: 1 type:
int
[pc: 6, pc: 21] local: __cobertura__branch__number__ index: 2 type:
int
[pc: 10, pc:121] local: key: 3 type: String

Cobertura changes the byte code (instruments) and sometimes the order of the above variables get mixed.

Local variable table:
[pc: 10, pc:121] local: key: 3 type: String
[pc: 6, pc: 21] local: this index: 0 type:com.example.ExampleAspect
[pc: 6, pc: 21] local: __cobertura__line__number__ index: 1 type:
int
[pc: 6, pc: 21] local: __cobertura__branch__number__ index: 2 type:
int

This is causing AspectJ to not behave properly resulting in 
"error at com.example.ExampleAspectjava::0 Cannot read debug info for
@Aspect to handle formal binding in pointcuts (please compile with 'javac
-g' or '<javac debug='true'.../>' in Ant)...."

Recommendation 1:
Cobertura folks need to fix the way instrumentation is performed so
that the local variable table data order is retained

Recommendation 2:
AspectJ LTW would have to look at the index field values of the local variables rather than assuming that the local variable entries are always added (to the byte code) in the increasing order of the index field values

Recommendation 3: Work around:
Instead of coding the logic within the Aspect method, re-factor the logic
into a new method.
@Around(XXXXXX)
public Object aspectAround(ProceedingJoinPoint pjp,.....)
{
return logic();
}

public Object logic()
{
String key = "XYZ";
// some more logic
return key;
}