Hi Yoel,
Yes, an NPE sounds like a bug to me. Thanks for offering to file a bug.
Thanks,
-Rick
On 9/4/13 4:09 PM, Yoel Spotts wrote:
I’m using derby 10.10.1.1 on windows and am encountering an issue when
shutting down derby. After tracking down the problem, there seems to
be a possible bug in the DRDAConnThread.java – before filing a jira
item, I wanted to run this by the community for feedback.
The issue manifests itself when shutting down derby – under certain
circumstances, a NullPointerException is thrown. Even worse – the
exception is “hidden” since the handling of the exception itself
throws an exception. This issue is not consistent in our tests and
presents unpredictably – most likely a timing issue. While I don’t
have a firm grasp of the exact circumstances that cause the exception
to be thrown, I believe it is clear that the handling of an exception
is less than ideal and leads to this exception. Tracing through the
code in DRDAConnThread.java will provide the best explanation:
1)Code enters parseSECCHK (line 3117) to perform security check on a
new session
2)All security checks pass and control continues to line 3357 to the call
database.getConnection().resetFromPool();
3)That method call generates an exception as derby is shutting down as
follows:
java.sql.SQLNonTransientConnectionException: No current connection.
at
org.apache.derby.impl.jdbc.SQLExceptionFactory40.getSQLException(SQLExceptionFactory40.java:77)
at org.apache.derby.impl.jdbc.Util.newEmbedSQLException(Util.java:148)
at org.apache.derby.impl.jdbc.Util.newEmbedSQLException(Util.java:164)
at org.apache.derby.impl.jdbc.Util.noCurrentConnection(Util.java:333)
at
org.apache.derby.impl.jdbc.EmbedConnection.checkIfClosed(EmbedConnection.java:2375)
at
org.apache.derby.impl.jdbc.EmbedConnection.setupContextStack(EmbedConnection.java:2588)
at
org.apache.derby.impl.jdbc.EmbedConnection.resetFromPool(EmbedConnection.java:2983)
at
org.apache.derby.impl.drda.DRDAConnThread.parseSECCHK(DRDAConnThread.java:3357)
at
org.apache.derby.impl.drda.DRDAConnThread.parseDRDAConnection(DRDAConnThread.java:1198)
at
org.apache.derby.impl.drda.DRDAConnThread.processCommands(DRDAConnThread.java:998)
at org.apache.derby.impl.drda.DRDAConnThread.run(DRDAConnThread.java:295)
Caused by: java.sql.SQLException: No current connection.
at
org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(SQLExceptionFactory.java:42)
at
org.apache.derby.impl.jdbc.SQLExceptionFactory40.wrapArgsForTransportAcrossDRDA(SQLExceptionFactory40.java:125)
at
org.apache.derby.impl.jdbc.SQLExceptionFactory40.getSQLException(SQLExceptionFactory40.java:71)
... 10 more
4)This gets caught in line 3365 and calls handleException
5)handleException attempts to inform the client of the exception and
then calls closeSession and close on lines 8759 and 8760.
*6)*closeSession() sets the *session* member variable to null. *This
is the crux of the issue *
7)After handleException is called, control returns to parseSECCHK()
and continues to line 3374 (as all security checks passed).
8)This line attempts to deference a member of *session* which has just
been set to null by closeSession (in step 6) !!
9)This will throw a NullPointerException which is passed up the stack
and eventually caught and handled on line 320
10)This handling calls handleException(e)
11)handleException then calls sendUnexpectedException which attempts
to dereference *session* once again on line 8794, which of course
throws a NullPointerException.
12)This NPE is never caught, thus handled by the
uncaughtExceptionHandler which by default terminates the thread (note
that this causes the above exception to step 3 to be “hidden” as only
this exception is bubbled to the uncaughtExceptionHandler)
13)However, we have set a default uncaughtExceptionHandler in our
application which terminates on an uncaught exception. This is
undesirable in this situation since we are only trying to terminate an
embedded derby instance, but do not wish our application to terminate.
However, this default behavior makes sense as an uncaught exception
usually indicates a serious error.
Thus, it seems that the handling of an exception thrown by
resetFromPool() needs work. I’m not sure what the “correct” behavior
should be but throwing a DRDAProtocolException.newDisconnectException
after handleException does “fix” the issue.
Shall I file a bug? Is there anything else I should be aware of?
Thanks
Yoel Spotts