Understanding how to resolve "Inconsistent stackmap frames" exception
Asked Answered
D

1

6

I get an exception on startup of the web application as guice is trying to construct the class mentioned.

java.lang.VerifyError: Inconsistent stackmap frames at branch target 2770 in method com.aptusi.apps.magazine.api.servlet.internal.EditorServlet.service(Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;Ljava/lang/String;Lcom/aptusi/persistence/runtime/framework/DboSession;)V at offset 200
at java.lang.Class.getDeclaredConstructors0(Native Method)
at java.lang.Class.privateGetDeclaredConstructors(Class.java:2483)
at java.lang.Class.getDeclaredConstructors(Class.java:1891)
at com.google.inject.spi.InjectionPoint.forConstructorOf(InjectionPoint.java:243)
at com.google.inject.internal.ConstructorBindingImpl.create(ConstructorBindingImpl.java:96)
at com.google.inject.internal.InjectorImpl.createUninitializedBinding(InjectorImpl.java:629)
at com.google.inject.internal.InjectorImpl.createJustInTimeBinding(InjectorImpl.java:845)
at com.google.inject.internal.InjectorImpl.createJustInTimeBindingRecursive(InjectorImpl.java:772)
at com.google.inject.internal.InjectorImpl.getJustInTimeBinding(InjectorImpl.java:256)
at com.google.inject.internal.InjectorImpl.getBindingOrThrow(InjectorImpl.java:205)
at com.google.inject.internal.InjectorImpl.getBinding(InjectorImpl.java:146)
at com.google.inject.internal.InjectorImpl.getBinding(InjectorImpl.java:66)
at com.google.inject.servlet.ServletDefinition.init(ServletDefinition.java:103)
at com.google.inject.servlet.ManagedServletPipeline.init(ManagedServletPipeline.java:82)
at com.google.inject.servlet.ManagedFilterPipeline.initPipeline(ManagedFilterPipeline.java:102)
at com.google.inject.servlet.GuiceFilter.init(GuiceFilter.java:172)`

I know about the -XX:-UseSplitVerifier and -noverify jvm options but I don't want to use as I want to ensure that all the code in this project is at least java version 7.

In order to do this It would be useful to understand where exactly this is occurring in my code, its not clear to me what the offset of 200 mentioned is but can it be related to a line number?

Also does anyone know of a way that I can find out the java versions of all classes on my classpath, I am using maven so there are a lot of dependencies, so I'm looking for an automated way of finding any classes on the classpath that may have been compiled to a lower java version than 1.7?

Debtor answered 1/10, 2013 at 13:26 Comment(0)
S
1

To find the version of a classfile, just look at the 8th byte of the classfile. It will be 51 for Java 7 classes. A framework like ASM will do this for you.

As far as the error goes, it means your classfile is malformed. How did you create these classes? Did you do any bytecode manipulation? If so, you probably have a bug in your code.

Stultz answered 1/10, 2013 at 13:49 Comment(24)
Thanks Antimony, problem is that this project depends on roughly 100 jars so I need a way to quickly verify that all classes within all jars conform to a certain version.Debtor
Just write a Python script (assuming you know where the jars are located).Stultz
It seems like the only way to verify this although I'm surprised that there is not tool for this allready.Debtor
Do you know how the offset relates to line number in class file?Debtor
@Debtor It doesn't have anything to do with line numbers. It refers to actual offset into the bytecode.Stultz
Cheers Antimony, in the end I went for the slightly more ad hoc solution of incrementally commenting out code to narrow down the culprit. Turned out to be the org.json:json dependency.Debtor
This bug is the pain of my existence. It keeps resurfacing seemingly at random, since I started compiling my project with JDK 7, using eclipse, maven, m2eclipse, app engine. In the past I just needed to make sure that all the jars were put by maven in the lib folder. But recently it occurs when I call some particular static methods within my code! and that's all part of the same project that's built with java 7Oesophagus
@ZiglioNZ If you aren't doing runtime bytecode modification, then the problem is that one or more of your classfiles is malformed. Your best bet is to write a script to load every class and record which ones failed to load.Stultz
@Antimony, it's always the same static method that fails. But it fails randomly. Sometimes I rebuild a dependency and it goes away, sometimes it doesn't both on the development server, and on gae's production server. I don't understand what the GAE sdk does at runtime, it could do some bytecode modification. I've found a bug report from 2012 that showed that error happening with the Eclipse compiler, so I don't know. Some weird interactionOesophagus
This is just my newbie brain taking a guess, but have you got the datanucleus enhancer on? That modifies bytecode, I understand.Impeccable
@ZiglioNZ GAE uses a custom environment so that could cause problems. However, the fact that it's also appearing on your dev server shows that it's not a GAE problem. Anyway, what is that static method doing?Stultz
@Stultz I have two or three static methods for saving large files to the BlobStore. I'm logged on with Windows and all my files are on Linux, so I'll get back to you with the method signature. Also I've installed a bytecode viewer, I wonder how I can spot a stackmap mismatch. Is it between the caller and the callee? thank you for your interest, very appreciated!Oesophagus
@ZiglioNZ Are you running everything using the standard Hotspot JVM? Are you compiling com.google.appengine.api.blobstore.BlobKey yourself or using a provided classfile? Also can you post the classfile for BlobKey?Stultz
@Stultz Well this is interesting. BlobKey is part of the GAE SDK and the class file shows // class version 50.0 (50)Oesophagus
I've updated my gist with that class. It comes prebuilt with GAE's SDK jars. I run against Oracle's latest java 7 runtime. The interesting bit though is that if this error occurs on my development system, it also occurs on GAE's servers. I'm not entirely sure what version on java they run and what vendor they useOesophagus
@Stultz Good point, that's when a runtime verifier works right? I've gotta check. Also, I wonder how the verifier works in case some classes are version 51 with a stackmap, while some others arent, the GAE SDK ones. That means the verifier must fall back into the classic two pass oneOesophagus
Hotspot falls back to regular inference verification for pre 51.0 classfiles. That's what it's supposed to do.Stultz
@Stultz so, let's say my 51.0 class stackmap contains both 50.0 and 51.0 parameters, the legacy bytecode verifier runs, and that's what's failing? Anyway, I don't know what I've done but the problem has gone for now. I've gone to one of the dependencies and made sure they used the same GAE SDK version across. It doesn't leave me with a good feeling because I haven't really understood what caused the problem. I'm afraid it's beyond my understanding at this stage. I appreciate your help!Oesophagus
@Ziglio what do you mean by parameter versions? Version is a property of the entire classfile.Stultz
@Stultz I mean the classes that are listed in a StackMap frame. Some of them are 51.0 and others (from the GAE SDK) 50.0.Oesophagus
@Ziglio That doesn't matter at all. You could put the name of a 45.0 class in there for all the JVM cares. You could even put random garbage that doesn't refer to a real class at all, though you'll probably get a loader error when the VM tries to load the referenced class.Stultz
@Antimony, I thought the verifier would recursively check all the stackmaps of classes within stackmaps but perhaps I don't understand how the verifier works. One of my dependencies was "built against" a different version of the GAE SDK. There must have been somewhere along the chain that failed the bytecode verifierOesophagus
@Ziglio It checks all the stackmaps within the class being loaded. Sometimes verification will result in other classes being loaded in which case those classes will be verified too. But it's basically a separate process. Anyway, do you have a minimal set of classfiles that causes the error? If so I might take a look at them to see if I can figure out where the problem is.Stultz
@Stultz I'll try and reproduce to bug. Might send you a private message here or on githubOesophagus

© 2022 - 2024 — McMap. All rights reserved.