Skip to content

JVM crash: java.lang.VerifyError: Bad type on operand stack #14164

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

Closed
strelec opened this issue Dec 23, 2021 · 14 comments · Fixed by #14919
Closed

JVM crash: java.lang.VerifyError: Bad type on operand stack #14164

strelec opened this issue Dec 23, 2021 · 14 comments · Fixed by #14919
Assignees
Milestone

Comments

@strelec
Copy link

strelec commented Dec 23, 2021

Compiler version

3.1.0

Minimized code

It seems that a combination of two factors trigger this bug:

  1. skipping a parameter via named parameters
  2. using for comprehension / lambda
class Base(a: String = "x", param: String = "")

class Child extends Base(param = {
  (for(x <- Seq("a")) yield x)
  "param"
})

new Child

Output

java.lang.VerifyError: Bad type on operand stack
Exception Details:
  Location:
    Playground$Child.<init>()V @25: invokedynamic
  Reason:
    Type uninitializedThis (current frame, stack[1]) is not assignable to 'Playground$Child'

Looks somewhat siliar to #2163

Expectation

Code runs with no output.

@som-snytt
Copy link
Contributor

My copy/paste skills are getting rusty.

➜  scala i14164.scala
Child@839755f
➜  cat i14164.scala

class Base(a: String = "x", param: String = "")

class Child extends Base(param = {
  (for(x <- Seq("a")) yield x)
  "param"
})

@main def test() = println {
  new Child
}
➜  java -version
openjdk version "17.0.1" 2021-10-19
OpenJDK Runtime Environment (build 17.0.1+12-39)
OpenJDK 64-Bit Server VM (build 17.0.1+12-39, mixed mode, sharing)
➜  scalac -version
Scala compiler version 3.1.0 -- Copyright 2002-2021, LAMP/EPFL

@strelec
Copy link
Author

strelec commented Dec 24, 2021

@som-snytt
Copy link
Contributor

Reproducer

package api {
  package object runtime {
    trait ScastieApp extends App
  }
}

import _root_.api.runtime._
object Playground extends ScastieApp {
  class Base(a: String = "x", param: String = "")

  class Child extends Base(param = {
    (for(x <- Seq("a")) yield x)
    "param"
  })

  new Child
}
object Main {
  val playground = Playground
  def main(args: Array[String]): Unit = {
    playground.main(Array())
  }
}

App is not involved.

object Playground {
  class Base(a: String = "x", param: String = "")

  class Child extends Base(param = {
    (for(x <- Seq("a")) yield x)
    "param"
  })

  new Child
}
@main def test() = Playground

says

➜  scala i14164d.scala
Exception in thread "main" java.lang.VerifyError: Bad type on operand stack
Exception Details:
  Location:
    Playground$Child.<init>()V @25: invokedynamic
  Reason:
    Type uninitializedThis (current frame, stack[1]) is not assignable to 'Playground$Child'
  Current Frame:
    bci: @25
    flags: { flagThisUninit }
    locals: { uninitializedThis }
    stack: { 'scala/collection/SeqOps', uninitializedThis }
  Bytecode:
    0000000: b200 14b6 0018 b200 1d04 bd00 1f59 0312
    0000010: 2153 b600 25b6 002b 2aba 003f 0000 b900
    0000020: 4502 0057 1247 4cb2 004a b600 4e4d 2a2c
    0000030: 2bb7 0051 b1

        at java.base/java.lang.Class.getDeclaredMethods0(Native Method)
        at java.base/java.lang.Class.privateGetDeclaredMethods(Class.java:3402)
        at java.base/java.lang.Class.getMethodsRecursive(Class.java:3543)
        at java.base/java.lang.Class.getMethod0(Class.java:3529)
        at java.base/java.lang.Class.getMethod(Class.java:2225)
        at dotty.tools.scripting.ScriptingDriver.collectMainMethods$3(ScriptingDriver.scala:79)
        at dotty.tools.scripting.ScriptingDriver.$anonfun$3(ScriptingDriver.scala:88)
        at scala.collection.immutable.List.flatMap(List.scala:293)
        at dotty.tools.scripting.ScriptingDriver.detectMainClassAndMethod(ScriptingDriver.scala:89)
        at dotty.tools.scripting.ScriptingDriver.compileAndRun(ScriptingDriver.scala:34)
        at dotty.tools.scripting.Main$.main(Main.scala:43)
        at dotty.tools.MainGenericRunner$.run$1(MainGenericRunner.scala:168)
        at dotty.tools.MainGenericRunner$.main(MainGenericRunner.scala:175)
        at dotty.tools.MainGenericRunner.main(MainGenericRunner.scala)

@odersky
Copy link
Contributor

odersky commented Mar 13, 2022

This looks like a duplicate of an issue I fixed recently. I verified that this works now.

@odersky odersky closed this as completed Mar 13, 2022
@griggt
Copy link
Contributor

griggt commented Mar 13, 2022

I verified that this works now.

It still blows up for me:

Welcome to Scala 3.1.3-RC1-bin-SNAPSHOT-nonbootstrapped-git-5626f25 (1.8.0_292, Java OpenJDK 64-Bit Server VM).
Type in expressions for evaluation. Or try :help.

scala> class Base(a: String = "x", param: String = "")
     | 
     | class Child extends Base(param = {
     |   (for(x <- Seq("a")) yield x)
     |   "param"
     | })
     | 
     | new Child
// defined class Base
// defined class Child
java.lang.VerifyError: Bad type on operand stack
Exception Details:
  Location:
    rs$line$1$Child.<init>()V @25: invokedynamic
  Reason:
    Type uninitializedThis (current frame, stack[1]) is not assignable to 'rs$line$1$Child'
  Current Frame:
    bci: @25
    flags: { flagThisUninit }
    locals: { uninitializedThis }
    stack: { 'scala/collection/SeqOps', uninitializedThis }
  Bytecode:
    0x0000000: b200 13b6 0017 b200 1c04 bd00 1e59 0312
    0x0000010: 2053 b600 24b6 002a 2aba 003e 0000 b900
    0x0000020: 4402 0057 1246 4cb2 0049 b600 4d4d 2a2c
    0x0000030: 2bb7 0050 b1

  ... 65 elided

@som-snytt
Copy link
Contributor

It compiles but my local dotty still says

➜  snips ~/projects/dotty/bin/scala i14164d.scala
Exception in thread "main" java.lang.VerifyError: Bad type on operand stack
Exception Details:
  Location:
    Playground$Child.<init>()V @25: invokedynamic
  Reason:
    Type uninitializedThis (current frame, stack[1]) is not assignable to 'Playground$Child'
  Current Frame:
    bci: @25
    flags: { flagThisUninit }
    locals: { uninitializedThis }
    stack: { 'scala/collection/SeqOps', uninitializedThis }
  Bytecode:
    0000000: b200 14b6 0018 b200 1d04 bd00 1f59 0312
    0000010: 2153 b600 25b6 002b 2aba 003f 0000 b900
    0000020: 4502 0057 1247 4cb2 004a b600 4e4d 2a2c
    0000030: 2bb7 0051 b1

        at java.base/java.lang.Class.getDeclaredMethods0(Native Method)
        at java.base/java.lang.Class.privateGetDeclaredMethods(Class.java:3402)
        at java.base/java.lang.Class.getMethodsRecursive(Class.java:3543)
        at java.base/java.lang.Class.getMethod0(Class.java:3529)
        at java.base/java.lang.Class.getMethod(Class.java:2225)
        at dotty.tools.scripting.Util$.collectMainMethods$1(Util.scala:37)
        at dotty.tools.scripting.Util$.$anonfun$3(Util.scala:46)
        at scala.collection.immutable.List.flatMap(List.scala:293)
        at dotty.tools.scripting.Util$.detectMainClassAndMethod(Util.scala:47)
        at dotty.tools.scripting.ScriptingDriver.compileAndRun(ScriptingDriver.scala:28)
        at dotty.tools.scripting.Main$.main(Main.scala:45)
        at dotty.tools.MainGenericRunner$.run$1(MainGenericRunner.scala:248)
        at dotty.tools.MainGenericRunner$.main(MainGenericRunner.scala:267)
        at dotty.tools.MainGenericRunner.main(MainGenericRunner.scala)

where

➜  snips cat i14164d.scala

object Playground:
  class Base(a: String = "x", param: String = "")

  class Child extends Base(param = {
    for (x <- Seq("a")) yield x
    "param"
  })
end Playground
@main def test() = Playground

I have not yet re-spooled whatever insight I may have had last year. I just typed in the command at the prompt.

Oh, I guess it's a problem induced by scripting, because normally:

➜  snips ~/projects/dotty/bin/scalac -d /tmp i14164d.scala
resolveOverloaded List(TermRef(TermRef(ThisType(TypeRef(NoPrefix,module class scala)),object Predef),method println), TermRef(TermRef(ThisType(TypeRef(NoPrefix,module class scala)),object Predef),method println)) FunProto(Ident(Playground) => class dotty.tools.dotc.typer.ProtoTypes$CachedIgnoredProto)
resolveOverloaded.narrowedApplicable List(TermRef(TermRef(ThisType(TypeRef(NoPrefix,module class scala)),object Predef),method println))
➜  snips ~/projects/dotty/bin/scala -cp /tmp test
Playground$@62e136d3

where my extra debug is unrelated. I added a println out of paranoia.

@odersky
Copy link
Contributor

odersky commented Mar 13, 2022

I tried with a standalone application, not a script. @griggt @som-snytt Does that also crash for you?

@odersky odersky reopened this Mar 13, 2022
@som-snytt
Copy link
Contributor

som-snytt commented Mar 13, 2022

@griggt jinx. The other family members were shuffling out the door so I didn't hit the button first.

Also I just re-re-ran with a clean repo, it fails only with scala foo.scala, not compile and run.

@odersky
Copy link
Contributor

odersky commented Mar 13, 2022

So should this be area:repl then?

@som-snytt
Copy link
Contributor

som-snytt commented Mar 13, 2022

The script runner is not the REPL! he said, defensively.

unless @griggt has already fixed it, I'll take a look today.

@griggt
Copy link
Contributor

griggt commented Mar 13, 2022

@som-snytt go for it!

It seems to me that the failure only occurs in presence of the wrapper object injected by the REPL / Scastie?

@strelec
Copy link
Author

strelec commented Apr 12, 2022

This is not just REPL, I am getting this error with production code.

@som-snytt
Copy link
Contributor

@strelec I will get back to this. To fail, it needs both the enclosing outer template and to force loading the Child. (My @main skipped new Child, but the reflective runner induced the verifier.)

I did check that ScriptingDriver produces the same trees, it's just running it differently.

Also the script runner is not the REPL.

odersky added a commit to dotty-staging/dotty that referenced this issue Apr 13, 2022
Super calls with default and named parameters can have
lifted arguments in val defs preceding the constructor call.
If these are complex, we need to hoist them out as well.

Fixes scala#14164
@odersky
Copy link
Contributor

odersky commented Apr 13, 2022

I found the root cause: We forgot about lifted parameters when hoisting out supercall arguments.

michelou pushed a commit to michelou/scala3 that referenced this issue Apr 25, 2022
Super calls with default and named parameters can have
lifted arguments in val defs preceding the constructor call.
If these are complex, we need to hoist them out as well.

Fixes scala#14164
@Kordyjan Kordyjan added this to the 3.2.0 milestone Aug 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants