Strange StackOverFlowError for Proxy class
bluegol Jul 13, 2016 8:50 PMHi Andrew,
(It's me again.) Not really a narrowed-down report, but I'd like to share in case anyone has any idea.
Background: I'm trying to trace all jdbc prepared statements (among other things.)
The target app is an in-house jsp on tomcat, using myBatis, Spring framework, log4jdbc and so on.
Specifically, I have rules:
RULE pstmt reserve start
INTERFACE ^java.sql.Connection
METHOD prepareStatement
AT ENTRY
IF TRUE
DO
reserve(true, com.brainzsquare.apm.TraceItem.TIT_JDBC_PSTMT);
ENDRULE
RULE pstmt start
INTERFACE ^java.sql.Connection
METHOD prepareStatement
AT EXIT
IF TRUE
DO
traceln(">>>>>> " + $CLASS);
start(true, $!, com.brainzsquare.apm.TraceItem.TIT_JDBC_PSTMT, null);
ENDRULE
The function reserve increases a counter (attached to the type given as the second parameter),
and the function start decreases a counter, and if the counter becomes 0, it creates a TraceItem
and saves it.
It works with other types (servlet, jdbc connections, etc.) and other instances of the prepared statement.
But I received the following error in some of the trace (only relevant logs are shown):
...
Installed rule using default helper : pstmt reserve start
08:57:56.302 [localhost-startStop-1] INFO com.brainzsquare.apm.agent.Main - rese
rved. type: JDBC_PSTMT, ...
08:57:56.324 [localhost-startStop-1] INFO com.brainzsquare.apm.agent.Main - not
reserved. isStart: true, type: JDBC_PSTMT, counter: 2
... (skipped counters 3, 4, 5, 6)
08:57:56.441 [localhost-startStop-1] INFO com.brainzsquare.apm.agent.Main - not
reserved. isStart: true, type: JDBC_PSTMT, counter: 7
... (callstack to be shown later)
Installed rule using default helper : pstmt start
>>>>>> org.postgresql.jdbc3g.Jdbc3gConnection
08:57:56.605 [localhost-startStop-1] INFO com.brainzsquare.apm.agent.Main - not
started. target: <class org.postgresql.jdbc3g.Jdbc3gPreparedStatement>1226825917
:select z_myid as z_infraid ...
order by z_myid asc, type:JDBC_PSTMT, counter: 6
... (skipped counters 5, 4, 3, 2)
Installed rule using default helper : pstmt start
>>>>>> org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper
08:57:56.717 [localhost-startStop-1] INFO com.brainzsquare.apm.agent.Main - not
started. target: <class org.apache.commons.dbcp.DelegatingPreparedStatement>7967
80858:net.sf.log4jdbc.PreparedStatementSpy@2f7de93a, type:JDBC_PSTMT, counter: 1
Installed rule using default helper : pstmt start
>>>>>> com.sun.proxy.$Proxy77
*** java.lang.instrument ASSERTION FAILED ***: "!errorOutstanding" with message
transform method call failed at JPLISAgent.c line: 844
... ---------------------------------------------------------- (this appears total 12 times in a row)
pstmt start : java.lang.StackOverflowError
And when the counter is 7, i.e, when the callstack is deepest, it is:
org.postgresql.jdbc3g.Jdbc3gConnection.prepareStatement(Jdbc3gConnection.java)
org.postgresql.jdbc3.AbstractJdbc3Connection.prepareStatement(AbstractJdbc3Connection.java:274)
org.postgresql.jdbc2.AbstractJdbc2Connection.prepareStatement(AbstractJdbc2Connection.java:301)
net.sf.log4jdbc.ConnectionSpy.prepareStatement(ConnectionSpy.java:388)
org.apache.commons.dbcp.DelegatingConnection.prepareStatement(DelegatingConnection.java:281)
org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.prepareStatement(PoolingDataSource.java:313)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:497)
org.apache.ibatis.logging.jdbc.ConnectionLogger.invoke(ConnectionLogger.java:50)
com.sun.proxy.$Proxy77.prepareStatement(Unknown Source)
So it seems the counter logic works well.
I'd like to emphasize that the function "start" works fine in other cases. No recursion is in its logic. Also I tried doubling up jvm stack size,
only to get the same error at the same place.
After banging my head against my desk for some time, I realized the class in question is a Proxy class. So I changed my rule:
RULE pstmt reserve start
INTERFACE ^java.sql.Connection
METHOD prepareStatement
AT ENTRY
IF classNameOK($CLASS)
DO
reserve(true, com.brainzsquare.apm.TraceItem.TIT_JDBC_PSTMT);
ENDRULE
RULE pstmt start
INTERFACE ^java.sql.Connection
METHOD prepareStatement
AT EXIT
IF classNameOK($CLASS)
DO
traceln(">>>>>> " + $CLASS);
start(true, $!, com.brainzsquare.apm.TraceItem.TIT_JDBC_PSTMT, null);
ENDRULE
so that the rules skip "com.sun.proxy.*" classes. Then it worked! (Of course, by adding that rule, lots of
states are changed and I can't be 100% sure. But it worked in this specific case, and all other trace injection
worked without problem in my case...)
(Question #1) Do you have any suspicion that proxy classes might have conflict with byteman? Or do you have any idea why
StackOverFlowError occurred? (I'm 99% sure that it's not due to recursion, since I don't have any.)
Now why do I suspect proxy classes? I checked my rules with byteman-submit.jar -l, which shows lots of TypeWarningExceptions
involving proxy classes: unknown local variable $this, no matching injection, and esp.
failed to find any matching trigger method in class com.sun.proxy.$Proxy77.
(Question #2) Are these TypeWarningException with proxy classes harmless?
Best,
Jahwan