JDK-7092736 : java.lang.VerifyError: method: next signature: ()L Incompatible object argument
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 6u26
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: linux
  • CPU: x86
  • Submitted: 2011-09-20
  • Updated: 2012-09-06
  • Resolved: 2011-09-20
Related Reports
Duplicate :  
Description
FULL PRODUCT VERSION :
java version "1.6.0_26"
Java(TM) SE Runtime Environment (build 1.6.0_26-b03)
Java HotSpot(TM) Server VM (build 20.1-b02, mixed mode)


ADDITIONAL OS VERSION INFORMATION :
Reproduced on:
1) Linux 2.6.35-30-generic #56-Ubuntu SMP Mon Jul 11 20:00:22 UTC 2011 i686 GNU/Linux
2) (Mac OS X) Darwin Kernel Version 11.0.0

A DESCRIPTION OF THE PROBLEM :
In this method:

    public Iterable<Unit> all() {
        final Unit[] units = new Unit[] {new Unit()};
        final Ref<Integer> count = new Ref<Integer>(0);

        return new Iterable<Unit>() {
            @Override
            public Iterator<Unit> iterator() {
                return new Iterator<Unit>() {
                    @Override
                    public boolean hasNext() {
                        return false;
                    }

                    @Override
                    public Unit next() {
                        System.out.println("HERE I AM");
                        // this next line is the offending line - even though this code is NEVER executed!
                        // it has to do with the reference to units[count.t++]...
                        System.out.println(units[count.t++]);
                        return null;
                    }

                    @Override
                    public void remove() {
                    }
                };
            }
        };
    }

... the call to next() never gets calls but the java runtime will fail with a VerifyError because of the line: units[count.t++].

Any changes to the construct will make the runtime work.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Here is the source:


package sandbox;

import java.util.Iterator;

import org.junit.Test;

public class UnitTest {

  /**
   * works all the time
   */
  @Test
  public void sanity() {
    final Ref<Integer> count = new Ref<Integer>(0);
    for (Unit user : new Iterable<Unit>() {
      @Override
      public Iterator<Unit> iterator() {
        return new Iterator<Unit>() {
          @Override
          public boolean hasNext() {
            return false;
          }

          @Override
          public Unit next() {
            System.out.println(count.t++);
            return null;
          }

          @Override
          public void remove() {
          }
        };
      };
    }) {
      System.out.println(user);
    }
  }

  /**
   * Doesn't work when executed through maven (on mac ox X as well as Ubuntu
   * 10.10; jdk 1.6.0_26.)
   *
   * ... but works when run through Eclipse
   *
   * strangeJdk16Issue(sandbox.FileStorageTest): (class:
   * sandbox/FileStorageTest$2$1, method: next signature: ()Lsandbox/Unit;)
   * Incompatible object argument for function call
   *
   * seems to be related to the remove() call to deleteRecursive()
   */
  @Test
  public void strangeJdk16Issue() throws Exception {
    for (Unit unit : all()) {
      System.out.println(unit);
    }
  }

  public Iterable<Unit> all() {
    final Unit[] units = new Unit[] { new Unit() };
    final Ref<Integer> count = new Ref<Integer>(0);

    return new Iterable<Unit>() {
      @Override
      public Iterator<Unit> iterator() {
        return new Iterator<Unit>() {
          @Override
          public boolean hasNext() {
            return false;
          }

          @Override
          public Unit next() {
            System.out.println("HERE I AM");
            // this next line is the offending line - even though this code is
            // NEVER executed!
            // it has to do with the reference to units[count.t++]...
            System.out.println(units[count.t++]);
            return null;
          }

          @Override
          public void remove() {
          }
        };
      }
    };
  }

  
  private static class Unit {

  }

  
  public class Ref<T> {
    public T t;

    public Ref(T t) {
      this.t = t;
    }

    public Ref() {
    }
  }
  
}


2. I would suggest creating a maven project to simplify the execution; here is my pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>sandbox</groupId>
  <artifactId>jdk16-issue</artifactId>
  <version>1.0</version>
  <packaging>jar</packaging>

  <name>jdk16-issue</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <build>
    <plugins>
      <!--plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-enforcer-plugin</artifactId>
        <executions>
          <execution>
            <id>enforce-versions</id>
            <goals>
              <goal>enforce</goal>
            </goals>
            <configuration>
              <rules>
                <requireJavaVersion>
                  <version>1.6</version>
                </requireJavaVersion>
              </rules>
            </configuration>
          </execution>
        </executions>
      </plugin-->
      
      <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>2.3.2</version>
          <configuration>
            <compilerVersion>1.6</compilerVersion>
            <source>1.6</source>
            <target>1.6</target>
            <testSource>1.6</testSource>
            <testTarget>1.6</testTarget>
            <compilerArguments>
              <verbose/>
            </compilerArguments>
         </configuration>
      </plugin>
    
      <!--plugin>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.9</version>
        <configuration>
          <systemProperties>
          </systemProperties>
        </configuration>
      </plugin-->

    </plugins>
  </build>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.8.2</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>


3. mvn clean install


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -

-------------------------------------------------------------------------------
Test set: sandbox.UnitTest
-------------------------------------------------------------------------------
Tests run: 2, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.022 sec <<< FAILURE!
strangeJdk16Issue(sandbox.UnitTest)  Time elapsed: 0.003 sec  <<< ERROR!
java.lang.VerifyError: (class: sandbox/UnitTest$2$1, method: next signature: ()Lsandbox/UnitTest$Unit;) Incompatible object argument for function call
        at sandbox.UnitTest$2.iterator(UnitTest.java:66)
        at sandbox.UnitTest.strangeJdk16Issue(UnitTest.java:54)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
        at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
        at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
        at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:62)
        at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:140)
        at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:127)
        at org.apache.maven.surefire.Surefire.run(Surefire.java:177)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:345)
        at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:1009)


REPRODUCIBILITY :
This bug can be reproduced always.

CUSTOMER SUBMITTED WORKAROUND :
  Interestingly the problem does not show up when the testcase is run from Eclipse.

I compared the compiled classes between eclipse and maven and there are differences but I wasn't able to discern the way eclipse compiled the code.

Regardless, there seems to be a bug in either javac or java.