Debugging StackOverflowExceptions in Java

Problem

StackOverflowExceptions in Java and in other programming languages can be notoriously difficult to debug. The most troublesome attribute of these exceptions is that they occur in no specific place in the application. In specific, the location (class+line number) in which the exception is thrown does only point indirectly to the erroneous part of the application.

For instance, the StackOverflowException reported in the following stack trace …

Exception in thread “pool-1117-thread-1” java.lang.StackOverflowError

    at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(Unknown Source)

    at java.util.concurrent.locks.ReentrantLock.unlock(Unknown Source)

    at one.utils.jre.concurrent.JreConcurrency$4.unlock(JreConcurrency.java:146)

… has the same cause as this stack trace:

Exception in thread “pool-1115-thread-1” java.lang.StackOverflowError

    at java.lang.String.endsWith(Unknown Source)

    at mx.gwtutils.MxroGWTUtils.assertNoSlash(MxroGWTUtils.java:311)

    at nx.core.nodes.v01.ReferenceData.<init>(ReferenceData.java:34)

    at nx.core.Nx.reference(Nx.java:156)

Solution

The first sensible action is to run the application multiple times and identify common patterns in the reported stack traces. In particular, the overflow exception is most likely caused by an undesired recursive loop involving one or multiple method calls. The first case can usually easily be identified from the stack trace. For instance, in the following example there is probably something wrong with line 36 in the tested class.

The latter case, that of multiple involved method calls, is often the more interesting (to use a daring euphemisms). For instance, a recursive loop might occur in the following constellation:

method 1 -> method 2 -> … -> method 40 -> method 41 -> method 1

In this case, it is significantly more difficult to find the original cause of the problem, since, theoretically, the cause might be in any of the involved methods.

The useful construct ‘assert’ in combination with the capabilities of Java Exceptions can be of great help to pinpoint the error leading to undesired recursion. The following guard will check that the total depth of the stack trace is below a sensible threshold (in the example 799 nested method calls). If this threshold is violated, the application will terminate with a message hopefully of greater aid than Java’s StackOverflowException.

assert new Exception().getStackTrace().length < 800 : “Stack overflow for message: “+ message;

Adding a number of such asserts in the methods involved in the stack overflow can greatly speed up the process of identifying the cause of the error.

Notes

  • Asserts will only be evaluated when the JVM is started using the argument ‘-ea’
  • While asserts should be disabled by default in production deployments and therewith the additional guards inserted in the code should not affect application performance, the performance penalty of getting a stack trace in Java (new Exception().getStackTrace()) is very high. Therefore, one might consider adding an additional Boolean flag to these asserts to assure they are only invoked when one is actively searching for the cause of StackOverflowExceptions.

GWT Serialization: ‘Expected type ‘int’ but received an out-of-range value’

Problem

While the GWT application works fine in development mode, it reports a mysterious NumberFormatException exception in production mode upon deserialization of an RPC on the server side.

java.lang.NumberFormatException: Expected type ‘int’ but received an out-of-range value: -43400113595222000

at [..]ServerSerializationStreamReader.getNumberFormatException(ServerSerializationStreamReader.java:839)

Analysis

Apparently Java and JavaScript have a different definition of the capacity of the type int. JavaScript integers can hold larger values than allowed by Java integers. While usually testing the application in an Java environment can easily spot integer overflows occurring for Java integers, generated integer values can cause problems in some special cases. In specific the algorithm employed by GWT to calculate the hash codes of objects (Object.hashCode()) is prone to produce integer values, which exceed the maximum value for integers in Java. If this occurs, abovementioned exception might be cast during deserialization of incoming Objects with int fields.

Solution

First it boils down to finding the ‘int’ field of the serializable object, which is sent over the RPC wire, causing the exception. Unfortunately the exception provided by the GWT deserialization logic is not very helpful in this cause. A good starting point is to search for integer fields containing hash codes. For instance using the eclipse search as shown below:

After the integer field causing the overflow has been located, all assignments to this field must be checked whether they might cause a too large ‘int’ value to be assigned. For instance, the following assignment might lead to such a faulty assignment:

this.versionHash = this.generateHashCode();

Adding a binary mask to this assignment makes it ‘safe’ in preventing integer overflows:

this.versionHash = this.generateHashCode() & 0xffffffff;

Resources

Issue 4263: GWT Serialization issue

GWT: ‘A widget that has an existing parent widget may not be added to the detach list’

Problem

When wrapping an existing DOM element with a GWT widget (e.g. Button.wrap(…), HTML.wrap(…), etc), the GWT module will not load and report the exception like the following:

java.lang.AssertionError: A widget that has an existing parent widget may not be added to the detach list
at com.google.gwt.user.client.ui.RootPanel.detachOnWindowClose(RootPanel.java:136)
at com.google.gwt.user.client.ui.Label.wrap(Label.java:130)

Analysis

In GWT it does not seem to be possible, to wrap an element in the document’s DOM if any of its parents has been wrapped with a GWT widget before. For instance, see for the following HTML document …

<div style=”display: noneid=“outer_element”>

        <form class=“well”>

            <label><i class=“icon-exclamation-sign”></i> An error occurred while requesting your API key.</label>

            <div id=“inner_element”>No error message.</div>

        </form>

        </div>

… if we first wrap the element “outer_element” and then the element “inner_element” as in the following …

final HTML errorForm = HTML.wrap(DOM.getElementById(“outer_element”));

       final Label errorMessage = Label.wrap(DOM.getElementById(“inner_element”));

.. an exception will be thrown, since “outer_element” is the parent in the DOM of “inner_element“.

Solution

The exception can easily be prevented by wrapping DOM elements as GWT widgets from the inside out. So, the elements nested the deepest in the DOM will be wrapped first. Therefore, the example above will work smoothly, if the order in which the elements are wrapped is reversed, so that the inner element “inner_element” is wrapped before the outer element “outer_element“.

 // inner element must be wrapped BEFORE outer element

        final Label errorMessage = Label.wrap(DOM.getElementById(“inner_element”));

        final HTML errorForm = HTML.wrap(DOM.getElementById(“outer_element”));

References
gwt – How to add a custom widget to an element – Stack Overflow

How to wrap an existing div into an HTML widget ? – Google Web Toolkit | Google

java – How to mix html with gwt widgets? – Stack Overflow