Skip to content

Compiling code with Enums in without doing a clean compile causes runtime VerifyError #6664

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
j-mie6 opened this issue Jun 11, 2019 · 4 comments

Comments

@j-mie6
Copy link

j-mie6 commented Jun 11, 2019

When compiling code with Enums, unless a clean compile is done, then at runtime when an Enum is encountered (for example, here I have an enum Operator ...) an error like the following is triggered:

[error] (run-main-b) java.lang.VerifyError: Bad type on operand stack
[error] Exception Details:
[error]   Location:
[error]     compiler/Parser.createTable()Lscala/collection/immutable/List; @10: invokevirtual
[error]   Reason:
[error]     Type 'compiler/expr/Operator$' (current frame, stack[3]) is not assignable to 'compiler/expr/Operator'
[error]   Current Frame:
[error]     bci: @10
[error]     flags: { }
[error]     locals: { 'compiler/ChimeraParser' }
[error]     stack: { uninitialized 0, uninitialized 0, 'scala/Predef$', 'compiler/expr/Operator$' }
[error]   Bytecode:
[error]     0000000: bb00 4a59 b200 b3b2 02bf b602 c3b6 02c7
[error]     0000010: b702 cab9 02cf 0100 b202 d2b9 02d8 0200
[error]     0000020: c002 da2a ba02 e300 00b2 02e8 b602 ecb6
[error]     0000030: 02ef c002 dab0

This is running 0.16.0-RC3 cross compiling with a 2.12.8 library.

@smarter
Copy link
Member

smarter commented Jun 11, 2019

Can you provide a minimal project that reproduces the problem ?

@j-mie6
Copy link
Author

j-mie6 commented Jun 12, 2019

Here you go!

minimal-bug2.zip

This is a fun one! Two files are necessary, no cross-compilation necessary. valueOf is at fault! Run the following commands:

bash> sbt
sbt> ;clean;compile
sbt> runMain foo.Detonator

This should run fine and produce "ok!". Now edit Detonator.scala by adding whitespace or something. Run the following:

sbt> compile
sbt> runMain foo.Detonator

And boom!

info] Running foo.Detonator 
[error] (run-main-1) java.lang.VerifyError: Bad type on operand stack
[error] Exception Details:
[error]   Location:
[error]     foo/Detonator$.boom()V @5: invokevirtual
[error]   Reason:
[error]     Type 'foo/Bomb$' (current frame, stack[0]) is not assignable to 'foo/Bomb'
[error]   Current Frame:
[error]     bci: @5
[error]     flags: { }
[error]     locals: { 'foo/Detonator$' }
[error]     stack: { 'foo/Bomb$', 'java/lang/String' }
[error]   Bytecode:
[error]     0000000: b200 1f12 21b6 0027 57b1               
[error] java.lang.VerifyError: Bad type on operand stack
[error] Exception Details:
[error]   Location:
[error]     foo/Detonator$.boom()V @5: invokevirtual
[error]   Reason:
[error]     Type 'foo/Bomb$' (current frame, stack[0]) is not assignable to 'foo/Bomb'
[error]   Current Frame:
[error]     bci: @5
[error]     flags: { }
[error]     locals: { 'foo/Detonator$' }
[error]     stack: { 'foo/Bomb$', 'java/lang/String' }
[error]   Bytecode:
[error]     0000000: b200 1f12 21b6 0027 57b1               
[error] 
[error]         at foo.Detonator.main(Detonator.scala)
[error]         at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[error]         at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[error]         at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[error]         at java.base/java.lang.reflect.Method.invoke(Method.java:566)

@bishabosha
Copy link
Member

bishabosha commented Nov 7, 2019

Ok so I found that under incremental compilation, Detonator.boom is rewritten as shown by this diff:

@@ -114,10 +114,10 @@ public final class foo.Detonator$ implements scala.Serializable
  public void boom();
      descriptor: ()V
      flags: ACC_PUBLIC
      Code:
        stack=2, locals=1, args_size=1
           0: getstatic     #31                 // Field foo/Bomb$.MODULE$:Lfoo/Bomb$;
           3: ldc           #33                 // String Kaboom
-          5: invokevirtual #39                 // Method foo/Bomb$.valueOf:(Ljava/lang/String;)Lfoo/Bomb;
+          5: invokevirtual #39                 // Method foo/Bomb.valueOf:(Ljava/lang/String;)Lfoo/Bomb;
           8: pop
           9: return

The rewritten code tries to invokevirtual the static method foo/Bomb.valueOf, instead of the virtual method foo/Bomb$.valueOf, and the types of the arguments no longer match

@ekrich
Copy link
Contributor

ekrich commented Dec 26, 2019

Any progress on this issue? This should fix my issue with serialization and allow all my tests to pass.
Reference as above: ekrich/sconfig#55

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

No branches or pull requests

5 participants