Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

java.lang.VerifyError: class scala.runtime.RichInt$$$$anon$$1 overrides final method foreach.(Lscala/Function1;)V #4575

Closed
scabug opened this issue May 12, 2011 · 20 comments

Comments

@scabug
Copy link

scabug commented May 12, 2011

=== What steps will reproduce the problem (please be specific and use wikiformatting)? ===

I reproduced the problem by deploying a WAR compiled with Scala 2.9.0 to Tomcat 7.0.12.

=== What is the expected behavior? ===

Successful initialisation.

=== What do you see instead? ===

791837-java.lang.VerifyError: class scala.runtime.RichInt$$$$anon$$1 overrides final method foreach.(Lscala/Function1;)V
791838-	at java.lang.ClassLoader.defineClass1(Native Method)
791839-	at java.lang.ClassLoader.defineClassCond(ClassLoader.java:632)
791840-	at java.lang.ClassLoader.defineClass(ClassLoader.java:616)
791841-	at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
791842-	at org.apache.catalina.loader.WebappClassLoader.findClassInternal(WebappClassLoader.java:2818)
791843-	at org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:1148)
791844-	at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1643)
791845-	at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1521)
791846-	at org.apache.catalina.startup.ContextConfig.checkHandlesTypes(ContextConfig.java:1956)

=== Additional information ===

To compensate for the lack of an isolated test case, here's some information (Alex Cruise provided some of it on IRC after I mentioned the initial error).

The source of the issue seems to be the following @bridge method in RichInt:

@bridge
def until(end: Int): Range with Range.ByOne = new Range(self, end, 1) with Range.ByOne

The problem is that Range defines a final foreach and Range.ByOne tries to override it.

Using javap, in Range.class, there is:

public final void foreach(scala.Function1);
  Code:
   Stack=2, Locals=4, Args_size=2
   0:   aload_0
...

and in RichInt$$$$anon$$1 which inherits from Range.Inclusive which inherits from Range, there is:

public void foreach(scala.Function1);
  Code:
   Stack=2, Locals=2, Args_size=2
   0:	aload_0
   1:	aload_1
   2:	invokestatic	SI-22; //Method scala/collection/immutable/Range$$ByOne$$class.foreach:(Lscala/collection/immutable/Range$$ByOne;Lscala/Function1;)V
...

=== What versions of the following are you using? ===

  • Scala: 2.9.0
  • Java: JDK 6 Update 25
  • Operating system: Linux
@scabug
Copy link
Author

scabug commented May 12, 2011

Imported From: https://issues.scala-lang.org/browse/SI-4575?orig=1
Reporter: @ijuma

@scabug
Copy link
Author

scabug commented May 13, 2011

@paulp said:
Minimally:

import annotation.bridge

class A {
  final def f() = ()
}
class B extends A {
  @bridge override def f() = ()
}

object Test {
  // java.lang.VerifyError: class B overrides final method f.()V
  def main(args: Array[String]) = new B f()
}

@scabug
Copy link
Author

scabug commented May 13, 2011

@ijuma said:
One way to look at it is there are two bugs here. One is in the compiler for not reporting an error and the other is in the standard libraries for having invalid @bridge method. I noticed that there's a second @bridge method in RichInt ('to') that also has the same issue. I've removed both and I'm in the process of recompiling the distribution to see if it solves my issue. I'll report back soon.

@scabug
Copy link
Author

scabug commented May 13, 2011

@ijuma said:
Removing the two mentioned @bridge methods in RichInt solves the problem indeed.

@scabug
Copy link
Author

scabug commented May 13, 2011

@odersky said:
It's undoubtedly a bug. I am now trying to find out how serious it is. Note that Paul's example is slightly off wrt situation with Range. Here is a more accurate rendition:

package scala

import annotation.bridge

class A {
  final def f(): A = new A
}
class B extends A {
  
  @bridge override def f(): B = new B
}

object Test {
  // java.lang.VerifyError: class B overrides final method f.()V
  def main(args: Array[String]) = {
    println(new B().f())  }
}

If I run this under java version "1.6.0_24" on MacOS, everything runs as it should:

/Users/odersky/workspace/scala/test/files/new> java -verify scala.Test
scala.A@28bb0d0d

Note that the bridge method was not called, but the original method in A was called instead.

If I would compile with an old binary that did refer to the bridge method signature directly, I would indeed get a VerifyError. So, we know for certain that bridge methods in Range are ineffective (without them you got a MissingMethodError, now you get a VerifyError, makes no practical difference).

But now I ask myself: Why did the bridge method not get verified, whereas in the original example it did? What's different between by setting and tomcats? Does tomcat somehow do different verification than java, or does Ismaels WAR contain some 2.8 code that calls the bridge method? In the first case, the error would be very serious, so that we'd have to put out a patch quickly.

@scabug
Copy link
Author

scabug commented May 13, 2011

@ijuma said:
From the stacktrace it looks to me that Tomcat is scanning the classpath (note that there is no code of mine in the stacktrace), which causes the invalid class to be loaded causing the verifier error. It looks very serious to me if my theory is correct.

@scabug
Copy link
Author

scabug commented May 13, 2011

@odersky said:
Sorry, my previous example was misleading, because it contains no override between the two f methods, so all is well. What happens is that there is indeed an illegal override in class Range$$ByOne. However, that class can be loaded only by calling another @bridge method in RichInt, and that method can be called only from 2.8 code. So, my question: Does TomCat not do lazy class loading? Is the stacktrace you showed me the whole stack, or is there some startup code for your servelet at the root?

@scabug
Copy link
Author

scabug commented May 13, 2011

@ijuma said:
As I said, I believe Tomcat does classpath scanning to find annotations and the like. The full stacktrace (as you see, only Tomcat code):

java.lang.VerifyError: class scala.runtime.RichInt$$$$anon$$1 overrides final method foreach.(Lscala/Function1;)V
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
        at org.apache.catalina.loader.WebappClassLoader.findClassInternal(WebappClassLoader.java:2818)
        at org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:1148)
        at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1643)
        at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1521)
        at org.apache.catalina.startup.ContextConfig.checkHandlesTypes(ContextConfig.java:1969)
        at org.apache.catalina.startup.ContextConfig.processAnnotationsStream(ContextConfig.java:1932)
        at org.apache.catalina.startup.ContextConfig.processAnnotationsJar(ContextConfig.java:1826)
        at org.apache.catalina.startup.ContextConfig.processAnnotationsUrl(ContextConfig.java:1785)
        at org.apache.catalina.startup.ContextConfig.processAnnotations(ContextConfig.java:1771)
        at org.apache.catalina.startup.ContextConfig.webConfig(ContextConfig.java:1254)
        at org.apache.catalina.startup.ContextConfig.configureStart(ContextConfig.java:881)
        at org.apache.catalina.startup.ContextConfig.lifecycleEvent(ContextConfig.java:316)
        at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119)
        at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:89)
        at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5103)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
        at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:812)
        at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:787)
        at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:607)
        at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:932)
        at org.apache.catalina.startup.HostConfig.deployWARs(HostConfig.java:723)
        at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:470)
        at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1322)
        at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:311)
        at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119)
        at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:89)
        at org.apache.catalina.util.LifecycleBase.setStateInternal(LifecycleBase.java:379)
        at org.apache.catalina.util.LifecycleBase.setState(LifecycleBase.java:324)
        at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1041)
        at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:774)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
        at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1033)
        at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:291)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
        at org.apache.catalina.core.StandardService.startInternal(StandardService.java:443)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
        at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:727)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
        at org.apache.catalina.startup.Catalina.start(Catalina.java:620)
        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.catalina.startup.Bootstrap.start(Bootstrap.java:303)
        at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:431)

@scabug
Copy link
Author

scabug commented May 13, 2011

@odersky said:
I agree it looks bad, then. We can take out the bridge methods but that would make Range binary incompatible. Or remove the final for Range's foreach and lose performance. It seems there's no good choice here.

@scabug
Copy link
Author

scabug commented May 13, 2011

@ijuma said:
Did you intend to mark the issue as fixed? I didn't see a commit and your comment seemed to indicate you were still considering the options.

@scabug
Copy link
Author

scabug commented May 13, 2011

@paulp said:
I don't know if it's relevant to any open questions, but in case it is: recall also that by default the scala jars are on the boot classpath now, which means the verifier is not run on them. You can put them on the user classpath with -nobootcp to the runner.

@scabug
Copy link
Author

scabug commented May 13, 2011

@ijuma said:
Yeah. I used the Java launcher to avoid this when I was testing things, but due to the lazy loading of classes, it wasn't easy to trigger the bug by just using Range (as Martin suggested).

@scabug
Copy link
Author

scabug commented May 13, 2011

@odersky said:
Sorry, closing was by accident. The issue is definitely not fixed!

@scabug
Copy link
Author

scabug commented May 13, 2011

@odersky said:
How about reverting to the previous Range design which had a ByOne class? In fact that might optimize better anyway.

@scabug
Copy link
Author

scabug commented May 13, 2011

@ijuma said:
I haven't looked at the commit log to confirm, but I recall that Iulian made some changes to improve the performance of Range and I think removing ByOne was one of the changes that improved the performance. Probably a good idea to include him in this conversation.

@scabug
Copy link
Author

scabug commented May 14, 2011

@dragos said:
I am (silently) watching the discussion on this ticket. It was me who removed ByOne, indeed in order to improve the optimizer's chance at fixing ranges. I don't remember all the issues I had, though. On the ohter hand, I believe all bridges should be dropped, together with the pretense of partial binary compatibility with 2.8. (nobody assumes it, nor cares, at this point -- of course, 2.9.1 is different).

@scabug
Copy link
Author

scabug commented May 16, 2011

@ijuma said:
Replying to [comment:20 dragos]:

On the ohter hand, I believe all bridges should be dropped, together with the pretense of partial binary compatibility with 2.8. (nobody assumes it, nor cares, at this point -- of course, 2.9.1 is different).

Agreed.

@scabug
Copy link
Author

scabug commented May 16, 2011

Bill Atkins (batkins) said:
I mean, is it really an option to drop bridges at this point? We have bridge methods and binary compatibility everywhere else; we can't just drop them in this one case, can we?

Is there a workaround at the moment - will this go away if I just recompile code that suffers from this bug with the 2.9.0 compiler?

@scabug
Copy link
Author

scabug commented May 17, 2011

@dragos said:
No, this won't go away if you recompile. The standard library that comes with Scala contains code that may trigger VerifyError. It won't happen in most cases, because that method is not normally called. But Tomcat scans the classpath and loads every class, eventually hitting the problematic case.

Martin already fixed it but forgot to close the ticket.

@scabug scabug closed this as completed May 18, 2011
@scabug
Copy link
Author

scabug commented May 18, 2011

Robbie Coleman (erraggy) said:
I was curious of if this fix has been made available...

I am still seeing this issue from within Glassfish:
{noformat}java.lang.VerifyError: class scala.runtime.RichInt$$anon$2 overrides final method foreach.(Lscala/Function1;)V
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:632)
at java.lang.ClassLoader.defineClass(ClassLoader.java:616)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
at org.glassfish.web.loader.WebappClassLoader.findClass(WebappClassLoader.java:925)
at org.glassfish.web.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1485)
at org.glassfish.web.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1368)
at scala.runtime.RichInt.until(RichInt.scala:25)
at net.liftweb.json.JsonAST$.quote(JsonAST.scala:397)
at net.liftweb.json.JsonAST$.render(JsonAST.scala:363)
at net.liftweb.json.JsonAST$$anonfun$3.apply(JsonAST.scala:367)
at net.liftweb.json.JsonAST$$anonfun$3.apply(JsonAST.scala:367)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:194)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:194)
at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59)
at scala.collection.immutable.List.foreach(List.scala:45)
at scala.collection.TraversableLike$class.map(TraversableLike.scala:194)
at scala.collection.immutable.List.map(List.scala:45)
at net.liftweb.json.JsonAST$.render(JsonAST.scala:367)
at net.liftweb.json.JsonAST$$anonfun$2.apply(JsonAST.scala:364)
at net.liftweb.json.JsonAST$$anonfun$2.apply(JsonAST.scala:364)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:194)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:194)
at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59)
at scala.collection.immutable.List.foreach(List.scala:45)
at scala.collection.TraversableLike$class.map(TraversableLike.scala:194)
at scala.collection.immutable.List.map(List.scala:45)
at net.liftweb.json.JsonAST$.render(JsonAST.scala:364)
at net.liftweb.json.JsonAST$$anonfun$3.apply(JsonAST.scala:367)
at net.liftweb.json.JsonAST$$anonfun$3.apply(JsonAST.scala:367)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:194)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:194)
at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59)
at scala.collection.immutable.List.foreach(List.scala:45)
at scala.collection.TraversableLike$class.map(TraversableLike.scala:194)
at scala.collection.immutable.List.map(List.scala:45)
at net.liftweb.json.JsonAST$.render(JsonAST.scala:367){noformat}

There is discussion on the scala-user group here:
[https://groups.google.com/d/msg/scala-user/LLBs0ocrMjA/m7yz8veOPbEJ]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant