5

The follow code compiles but causes a java.lang.VerifyError. The error occurs even if the run() method is not executed.

import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;


public class TestCase {

    public static void main(String[] args) {
        new TestCase().run();
    }

    public void run() {
        class Inner {

        }
        Map<String, Inner> map = new HashMap<>();
        Function<String, Inner> function = (name) -> {
            Inner i = map.get(name);
            if (i == null) {
                i = new Inner();
                map.put(name, i);
            }
            return i;

        };
        function.apply("test");
    }
}

The Error:

Exception in thread "main" java.lang.VerifyError: Bad type on operand stack
Exception Details:
  Location:
    TestCase.lambda$0(Ljava/util/Map;Ljava/lang/String;)LTestCase$1Inner; @20: invokespecial
  Reason:
    Type 'java/util/Map' (current frame, stack[2]) is not assignable to 'TestCase'
  Current Frame:
    bci: @20
    flags: { }
    locals: { 'java/util/Map', 'java/lang/String', 'TestCase$1Inner' }
    stack: { uninitialized 15, uninitialized 15, 'java/util/Map' }
  Bytecode:
    0000000: 2a2b b900 2d02 00c0 0032 4d2c c700 15bb
    0000010: 0032 592a b700 344d 2a2b 2cb9 0037 0300
    0000020: 572c b0                                
  Stackmap Table:
    append_frame(@33,Object[#50])

    at java.lang.Class.getDeclaredMethods0(Native Method)
    at java.lang.Class.privateGetDeclaredMethods(Class.java:2688)
    at java.lang.Class.getMethod0(Class.java:2937)
    at java.lang.Class.getMethod(Class.java:1771)
    at sun.launcher.LauncherHelper.validateMainClass(LauncherHelper.java:544)
    at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:526)

However, if I move the 'Inner' class to be an inner class of TestCase (instead of declared in a method), the error goes away. Or, if I use an anonymous class to define the Function, the error goes away. It seems to be an issue with a class declared in the method and the use of a lamba.

Is this a JVM bug? Or am I missing something? I am using Oracle's Java 8. The error happens both on the command line and within Eclipse 4.4.

EDIT: I upgraded to the latest JDK: java version "1.8.0_11" Java(TM) SE Runtime Environment (build 1.8.0_11-b12) Java HotSpot(TM) 64-Bit Server VM (build 25.11-b03, mixed mode)

When compile via javac manually and run it works fine. If I run the class compiled by Eclipse, it doesn't. So now I suspect that the Eclipse compiler has a bug.

anacron
  • 6,443
  • 2
  • 26
  • 31
dontocsata
  • 3,021
  • 3
  • 20
  • 19
  • Hmm... which OS and Java build? I've just tried it on Windows with Java 1.8.0-b132, Hotspot 64-Bit Server VM (build 25.0-b70, mixed mode) and it worked fine... – Jon Skeet Aug 15 '14 at 19:27
  • OSX 10.9: java version "1.8.0_05" Java(TM) SE Runtime Environment (build 1.8.0_05-b13) Java HotSpot(TM) 64-Bit Server VM (build 25.5-b02, mixed mode) – dontocsata Aug 15 '14 at 19:28
  • possible duplicate of [Reasons of getting a java.lang.VerifyError](http://stackoverflow.com/questions/100107/reasons-of-getting-a-java-lang-verifyerror) – afzalex Aug 15 '14 at 19:36
  • Just for everyone's info, close as I can tell it's doing the data flow analysis for a method, to assure that the data types reaching each location are the correct types. I *think* it's analyzing the lamda code, but can't be sure. It says that somewhere an `java/util/Map` object is being used where a `TestCase` is expected -- analogous to a cast check exception, only at verify time. (Note that the types of local variables don't count for these checks -- this would generally be a method call.) – Hot Licks Aug 15 '14 at 21:09
  • The failing instruction is at offset 0x14 : b70034. That's an invokespecial of the method at constant pool index 0x34. – Hot Licks Aug 15 '14 at 21:16
  • 1
    It seems to be a bug with eclipse indeed; I run into it myself as well and find a reference here: bugs.eclipse.org/bugs/show_bug.cgi?id=456481 – Luan Nico Jan 04 '15 at 01:44

1 Answers1

1

verify error is thrown when your compiler generates a code that is not verifiable by verifier. when the "verifier" detects that a class file, though well formed, contains some sort of internal inconsistency or security problem. So it is clearly an issue with your eclipse compiler as you have suggested. it is unable to properly compile these constructs.

faisalbhagat
  • 2,142
  • 24
  • 27