Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 344350 - [runtime][bcel] NPE in InstructionList.getInstructionHandles()
Summary: [runtime][bcel] NPE in InstructionList.getInstructionHandles()
Status: VERIFIED FIXED
Alias: None
Product: Objectteams
Classification: Tools
Component: OTJ (show other bugs)
Version: 0.8   Edit
Hardware: PC Linux
: P2 normal (vote)
Target Milestone: 2.1 M5   Edit
Assignee: Stephan Herrmann CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-04-29 17:03 EDT by Stephan Herrmann CLA
Modified: 2012-06-10 08:23 EDT (History)
0 users

See Also:


Attachments
proposed fix (2.43 KB, patch)
2011-04-29 18:13 EDT, Stephan Herrmann CLA
no flags Details | Diff
additional fixes (2.82 KB, patch)
2011-05-29 07:03 EDT, Stephan Herrmann CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Stephan Herrmann CLA 2011-04-29 17:03:01 EDT
Every once in a long while I observed an NPE with a stack trace like this one:
java.lang.NullPointerException
        at org.apache.bcel.generic.InstructionList.getInstructionHandles(InstructionList.java:1021)
        at org.apache.bcel.generic.InstructionList.findHandle(InstructionList.java:141)
        at org.apache.bcel.generic.MethodGen.<init>(MethodGen.java:194)
        at org.eclipse.objectteams.otre.ObjectTeamsTransformation.newMethodGen(ObjectTeamsTransformation.java:1369)
        at org.eclipse.objectteams.otre.BaseMethodTransformation.checkReplaceWickedSuper(BaseMethodTransformation.java:196)
        at org.eclipse.objectteams.otre.BaseMethodTransformation.doTransformCode(BaseMethodTransformation.java:181)
        at org.eclipse.objectteams.otre.jplis.ObjectTeamsTransformer.internalTransform(ObjectTeamsTransformer.java:201)
        at org.eclipse.objectteams.otre.jplis.ObjectTeamsTransformer.transform(ObjectTeamsTransformer.java:96)
        at org.eclipse.objectteams.otequinox.internal.hook.TransformerHook.transformClass(TransformerHook.java:397)
        at org.eclipse.objectteams.otequinox.internal.hook.TransformerHook.processClass(TransformerHook.java:337)

Today I succeeded in reproducing the NPE in a small example: Method 
org.apache.bcel.generic.InstructionHandle.getInstructionHandle(Instruction)
is not thread-safe: two threads could share the same InstructionHandle,
and as these are links in a linked list, this can mess up the list structure.
As an effect stored list length and actual number of linked cells don't match
and method InstructionList.getInstructionHandles() may run over the end.
=> NPE.
Comment 1 Stephan Herrmann CLA 2011-04-29 18:13:44 EDT
Created attachment 194414 [details]
proposed fix

This patch intercepts the byte codes of the affected bcel class and if all figures
match (including CRC) add the required "synchronized" flag to the buggy method.

Debugging a runtime workbench I could indeed see that the debugger saw
the method as synchronized.
Comment 2 Stephan Herrmann CLA 2011-04-29 19:18:18 EDT
Released as r1466,7
Comment 3 Stephan Herrmann CLA 2011-05-01 12:19:18 EDT
Verified for 0.8M7 using build 201105010849
Comment 4 Stephan Herrmann CLA 2011-05-29 06:12:27 EDT
Even in 2.0 RC2 the NPE still occurred, the difference between stack
traces seems to be irrelevant:

java.lang.NullPointerException
	at org.apache.bcel.generic.InstructionList.getInstructionHandles(InstructionList.java:1021)
	at org.apache.bcel.generic.InstructionList.findHandle(InstructionList.java:141)
	at org.apache.bcel.generic.MethodGen.<init>(MethodGen.java:208)
	at org.eclipse.objectteams.otre.ObjectTeamsTransformation.newMethodGen(ObjectTeamsTransformation.java:1369)
Comment 5 Stephan Herrmann CLA 2011-05-29 07:03:24 EDT
Created attachment 196842 [details]
additional fixes

This patch includes three more methods in the original strategy:

InstructionHandle.addHandle()
BranchHandle.getBranchHandle()
BranchHandle.addHandle()

All these methods access a static field (ih_list resp. bh_list) and must
be synchronized.
Comment 6 Stephan Herrmann CLA 2011-06-02 11:45:46 EDT
Resolved:
- log shows that both classes are now hot patched

- debugger shows that all these methods are indeed synchronized now,
  (with the exception of BranchHandle.addHandle() which is never
  called when running the OTDT).
Comment 7 Stephan Herrmann CLA 2011-06-02 11:46:03 EDT
Verified using build 201105311237
Comment 8 Stephan Herrmann CLA 2012-01-03 15:03:46 EST
I've once again seen the exception in the debugger after the logs
said that all hot-patches had been successfully applied.

From re-reading the comments and inspecting the sources I suspect
that synchronization is still broken because two of the methods
are non-static while synchronization against the class is required.
Comment 9 Stephan Herrmann CLA 2012-01-26 13:01:56 EST
A new solution has been pushed as commit 3b1be84439870630980a6b057ddcb99a827dfd79

Now we don't just patch individual bytes but replace the entire two class files. This enables us to add blocks like this
  synchronized(InstructionHandle.class) {
      ...
  }
Comment 10 Stephan Herrmann CLA 2012-02-19 13:20:41 EST
While previous patches made the issue less frequent it could still be observed once in a while.
As I could inspect a corrupted InstructionList in the debugger it looked exactly as caused by the lack of synchronization, although the patch had been applied.
This leaves me with only one explanation: synchronization on the non-volatile field ih_list isn't sufficient to force propagating the change between threads.

Since making the field volatile defies its purpose of optimization I'm removing those static lists altogether.
This has been pushed via commit 39cd15fb302def84ef176414e6c517fe0a037738
Comment 11 Stephan Herrmann CLA 2012-06-10 08:23:36 EDT
Issue hasn't been observed since the latest fix.

Thus marking as verified for 2.1.