What does the error message “Attempt to split long or double on the stack” indicate?

StackOverflow https://stackoverflow.com/questions/6098239

  •  09-09-2020
  •  | 
  •  

Question

I am getting the following error from my code:

Attempt to split long or double on the stack

I am clueless about the origin of this error and do not know how to debug it. What kind of problem does this indicate? How can I fix it?

[ERROR]  [Mon May 23 14:29:46 IST 2011]   [(class: org/apache/jsp/dashboard_jsp, method: _jspService signature:     (Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;)V) Attempt to split long or double on the stack]  [10.97.34.222] hddlntdsz2350  [ session not set ] 
java.lang.VerifyError: (class: org/apache/jsp/dashboard_jsp, method: _jspService signature: (Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;)V) Attempt to split long or double on the stack
at java.lang.Class.getDeclaredConstructors0(Native Method)
at java.lang.Class.privateGetDeclaredConstructors(Class.java:2389)
at java.lang.Class.getConstructor0(Class.java:2699)
at java.lang.Class.newInstance0(Class.java:326)
at java.lang.Class.newInstance(Class.java:308)
at org.jboss.web.tomcat.service.TomcatInjectionContainer.newInstance(TomcatInjectionContainer.java:273)

Problem Code : I have created a Model as given below

public class DashboardViewModel implements Serializable {

/** defalut serialization id */
private static final long serialVersionUID = 1L;

/**
 * Collection representing all the services
 */
private Map<Long, ServiceCustomerModel> serviceDataMap;

}

On a particular JSP page, I am doing following.

for (Long serviceId : dashboardViewModel.getServices()) {
           Service service = dashboardViewModel.getService(serviceId);
}

The getServices method in the above target class is as follows.

public Set<Long> getServices() {
    return this.serviceDataMap.keySet();
}

When including the above code in jsp. I do get the error. Otherwise, it works.

Further Investigataions :

I have updated the dashboard.jsp file with the following code snippet. I am not able to identify why, But this code is working.

ArrayList<Long> test = new ArrayList<Long>();
test.addAll(dashboardViewModel.getServices());
for (long serviceId : test) {
    Service service = dashboardViewModel.getService(serviceId);
}

Does this code makes any difference to the data?

Was it helpful?

Solution

The Java virtual machine performs additional verification on operations involving long and double data types, for the very simple reason that

A value of type long or type double occupies two consecutive local variables. Such a value may only be addressed using the lesser index. For example, a value of type double stored in the local variable array at index n actually occupies the local variables with indices n and n +1; however, the local variable at index n +1 cannot be loaded from. It can be stored into. However, doing so invalidates the contents of local variable n.

When the verifier determines that an incorrect instruction is used to access a long or a double variable (say, an instruction that attempts to treat the local variable at index n, as an integer or a float, which splits the double/long variable), then the said error is flagged.

Not a lot can be done in this case, except to fix the bytecode generator that generated this byte code. This may be the Java compiler itself, or any of the byte code manipulation frameworks like ASM, cglib or Javassist.

Edit:

After viewing the stacktrace, it appears that the class in question happens to be a generated servlet (from dashboard.jsp). It would be worthwhile to check if an upgrade of the JDK involving compilation of the translated JSP will resolve the issue.

OTHER TIPS

This seems to be a verification error that indicates that byte code being loaded is not entirely compatible with your vm/compiler. Most likely it comes from external library that you use or it may be generated in the process of your build and indicate a bug.

Do you use (directly or indirectly) any generated bytecode? It's often used with AOP.

Also Google gives a lot of hits for this error. Read them, see if anything fits the bill.

I can think of a case which involves autoboxing: are you trying to use autoboxing to store float's? If these end up autoboxed into Double's then when you're pulling them back from the stack (possibly due to a JVM bug) because float takes less bytes than double the byte size check fails and this error is thrown. This seems to be the case with openjdk looking at (some of) their source code -- I'm guessing the same would apply to the Sun (sorry, Oracle!) JDK.

This is a possible message of a java.lang.VerifyError, which is thrown when the "verifier" detects that a class file, though well formed, contains some sort of internal inconsistency or security problems.

The JVM specification notes (4.4.5):

All 8-byte constants take up two entries in the constant_pool table of the class file. If a CONSTANT_Long_info or CONSTANT_Double_info structure is the item in the constant_pool table at index n, then the next usable item in the pool is located at index n+2. The constant_pool index n+1 must be valid but is considered unusable.

So actually guess, that on class file has a constant pool that breaks this rule. This won't (shouldn't) happen with a normal java compiler but there are more ways to create and alter classfiles (AOP, BCEL, obfuscation or other programming languages). Try to get a stacktrace, it should give a hint to the offending classfile.

Further Reading

Can the issue be fixed by changing your code:

for (long serviceId : test) {
    Service service = dashboardViewModel.getService(serviceId);
}

into:

for (Long serviceId : test) {
    Service service = dashboardViewModel.getService(serviceId);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top