Navigation Menu

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

Value classes of Unit produces invalid bytecode #9240

Closed
scabug opened this issue Mar 21, 2015 · 4 comments
Closed

Value classes of Unit produces invalid bytecode #9240

scabug opened this issue Mar 21, 2015 · 4 comments
Assignees
Milestone

Comments

@scabug
Copy link

scabug commented Mar 21, 2015

Value classes appear to always expect a value to be allocated to the stack, even when their type is Unit, and the implementation does not allocate any value. This results in a java.lang.VerifyError.

This is sufficient to replicate the error:

class MyUnit(val unit: Unit) extends AnyVal

object Test {
  def main(args: Array[String]): Unit = {
    new MyUnit(()).toString
    // java.lang.VerifyError: Bad type on operand stack
    // Exception Details:
    //   Location:
    //     MyUnit.equals(Ljava/lang/Object;)Z @12: athrow
    //   Reason:
  }
}
@scabug
Copy link
Author

scabug commented Mar 21, 2015

Imported From: https://issues.scala-lang.org/browse/SI-9240?orig=1
Reporter: @propensive
Affected Versions: 2.10.5, 2.11.5
Attachments:

@lloydmeta
Copy link

lloydmeta commented Apr 14, 2017

I just ran into this one. On 2.11.x you get a VerifyError at runtime, but on 2.12.1 it's a compile time error:

scala.tools.asm.tree.analysis.AnalyzerException: While processing com/beachape/Funky$.equals$extension
        at scala.tools.nsc.backend.jvm.analysis.BackendUtils$AsmAnalyzer.<init>(BackendUtils.scala:40)
        at scala.tools.nsc.backend.jvm.opt.LocalOpt.removeUnreachableCodeImpl(LocalOpt.scala:488)
        at scala.tools.nsc.backend.jvm.opt.LocalOpt.removalRound$2(LocalOpt.scala:275)
        at scala.tools.nsc.backend.jvm.opt.LocalOpt.methodOptimizations(LocalOpt.scala:354)
        at scala.tools.nsc.backend.jvm.opt.LocalOpt.$anonfun$methodOptimizations$1(LocalOpt.scala:195)
        at scala.tools.nsc.backend.jvm.opt.LocalOpt.$anonfun$methodOptimizations$1$adapted(LocalOpt.scala:194)
        at scala.collection.TraversableOnce.$anonfun$foldLeft$1(TraversableOnce.scala:157)
        at scala.collection.TraversableOnce.$anonfun$foldLeft$1$adapted(TraversableOnce.scala:157)
        at scala.collection.Iterator.foreach(Iterator.scala:929)
        at scala.collection.Iterator.foreach$(Iterator.scala:929)
        at scala.collection.AbstractIterator.foreach(Iterator.scala:1406)
        at scala.collection.IterableLike.foreach(IterableLike.scala:71)
        at scala.collection.IterableLike.foreach$(IterableLike.scala:70)
        at scala.collection.AbstractIterable.foreach(Iterable.scala:54)
        at scala.collection.TraversableOnce.foldLeft(TraversableOnce.scala:157)
        at scala.collection.TraversableOnce.foldLeft$(TraversableOnce.scala:155)
        at scala.collection.AbstractTraversable.foldLeft(Traversable.scala:104)
        at scala.tools.nsc.backend.jvm.opt.LocalOpt.methodOptimizations(LocalOpt.scala:194)
        at scala.tools.nsc.backend.jvm.GenBCode$BCodePhase$Worker2.$anonfun$localOptimizations$1(GenBCode.scala:248)
        at scala.tools.nsc.backend.jvm.GenBCode$BCodePhase$Worker2.localOptimizations(GenBCode.scala:248)
        at scala.tools.nsc.backend.jvm.GenBCode$BCodePhase$Worker2.run(GenBCode.scala:267)
        at scala.tools.nsc.backend.jvm.GenBCode$BCodePhase.buildAndSendToDisk(GenBCode.scala:384)
        at scala.tools.nsc.backend.jvm.GenBCode$BCodePhase.run(GenBCode.scala:350)
        at scala.tools.nsc.Global$Run.compileUnitsInternal(Global.scala:1418)
        at scala.tools.nsc.Global$Run.compileUnits(Global.scala:1403)
        at scala.tools.nsc.Global$Run.compileSources(Global.scala:1398)
        at scala.tools.nsc.Global$Run.compile(Global.scala:1492)
        at xsbt.CachedCompiler0.run(CompilerInterface.scala:116)
        at xsbt.CachedCompiler0.run(CompilerInterface.scala:95)
        at xsbt.CompilerInterface.run(CompilerInterface.scala:26)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at sbt.compiler.AnalyzingCompiler.call(AnalyzingCompiler.scala:107)
        at sbt.compiler.AnalyzingCompiler.compile(AnalyzingCompiler.scala:53)
        at sbt.compiler.AnalyzingCompiler.compile(AnalyzingCompiler.scala:47)
        at sbt.compiler.MixedAnalyzingCompiler$$anonfun$compileScala$1$1.apply$mcV$sp(MixedAnalyzingCompiler.scala:50)
        at sbt.compiler.MixedAnalyzingCompiler$$anonfun$compileScala$1$1.apply(MixedAnalyzingCompiler.scala:50)
        at sbt.compiler.MixedAnalyzingCompiler$$anonfun$compileScala$1$1.apply(MixedAnalyzingCompiler.scala:50)
        at sbt.compiler.MixedAnalyzingCompiler.timed(MixedAnalyzingCompiler.scala:74)
        at sbt.compiler.MixedAnalyzingCompiler.compileScala$1(MixedAnalyzingCompiler.scala:49)
        at sbt.compiler.MixedAnalyzingCompiler.compile(MixedAnalyzingCompiler.scala:64)
        at sbt.compiler.IC$$anonfun$compileInternal$1.apply(IncrementalCompiler.scala:160)
        at sbt.compiler.IC$$anonfun$compileInternal$1.apply(IncrementalCompiler.scala:160)
        at sbt.inc.IncrementalCompile$$anonfun$doCompile$1.apply(Compile.scala:66)
        at sbt.inc.IncrementalCompile$$anonfun$doCompile$1.apply(Compile.scala:64)
        at sbt.inc.IncrementalCommon.cycle(IncrementalCommon.scala:32)
        at sbt.inc.Incremental$$anonfun$1.apply(Incremental.scala:72)
        at sbt.inc.Incremental$$anonfun$1.apply(Incremental.scala:71)
        at sbt.inc.Incremental$.manageClassfiles(Incremental.scala:99)
        at sbt.inc.Incremental$.compile(Incremental.scala:71)
        at sbt.inc.IncrementalCompile$.apply(Compile.scala:54)
        at sbt.compiler.IC$.compileInternal(IncrementalCompiler.scala:160)
        at sbt.compiler.IC$.incrementalCompile(IncrementalCompiler.scala:138)
        at sbt.Compiler$.compile(Compiler.scala:155)
        at sbt.Compiler$.compile(Compiler.scala:141)
        at sbt.Defaults$.sbt$Defaults$$compileIncrementalTaskImpl(Defaults.scala:886)
        at sbt.Defaults$$anonfun$compileIncrementalTask$1.apply(Defaults.scala:877)
        at sbt.Defaults$$anonfun$compileIncrementalTask$1.apply(Defaults.scala:875)
        at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
        at sbt.$tilde$greater$$anonfun$$u2219$1.apply(TypeFunctions.scala:40)
        at sbt.std.Transform$$anon$4.work(System.scala:63)
        at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:228)
        at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:228)
        at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:17)
        at sbt.Execute.work(Execute.scala:237)
        at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:228)
        at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:228)
        at sbt.ConcurrentRestrictions$$anon$4$$anonfun$1.apply(ConcurrentRestrictions.scala:159)
        at sbt.CompletionService$$anon$2.call(CompletionService.scala:28)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at java.lang.Thread.run(Thread.java:745)
Caused by: scala.tools.asm.tree.analysis.AnalyzerException: Error at instruction 37: Cannot pop operand off an empty stack.
        at scala.tools.asm.tree.analysis.Analyzer.analyze(Analyzer.java:302)
        at scala.tools.nsc.backend.jvm.analysis.BackendUtils$AsmAnalyzer.<init>(BackendUtils.scala:37)
        ... 76 more
Caused by: java.lang.IndexOutOfBoundsException: Cannot pop operand off an empty stack.
        at scala.tools.asm.tree.analysis.Frame.pop(Frame.java:235)
        at scala.tools.asm.tree.analysis.Frame.execute(Frame.java:338)
        at scala.tools.asm.tree.analysis.Analyzer.analyze(Analyzer.java:205)
        ... 77 more

@propensive
Copy link

In Scala 2.12, it's sufficient to write this to cause the compiler to crash:

class MyUnit(val unit: Unit) extends AnyVal

@som-snytt
Copy link

Or on 2.11 -Ybackend:GenBCode.

The new puzzler challenge is, what's the shortest crasher using arbitrary compiler options?

hrhino added a commit to hrhino/scala that referenced this issue Jun 11, 2017
…ing.

All sorts o' specialness going on here. Unit morphs into a BoxedUnit when
it's in a field, but void when it's the return type of a method, which is
expected. This means, though, that the unboxing method of a Unit-wrapping
value class has the signature `()V`, not `()Lscala/runtime/BoxedUnit`, so
attempting to use its value in the equals method spits out some wonderful
invalid bytecode, instead. Similar sadness occurs for Nothing and Null as
well.

The "solution" is to not even bother to check for equality, as we've only
got at most one legitimate value of each of these types. Because the code
is shared with `case class`es, this also changes the bytecode we generate
for them. Obviously this is an "unrelated change" as far as the bugs this
is meant to fix go, but it's innocuous enough as far as I can tell.

I also slipped a constructor call into the generated `ClassCastException`
that gets thrown when we are asked to emit a cast for a primitive type in
BCodeBodyBuilder, so we generate valid bytecode in that case. I've got no
idea how `NEW; DUP; ATHROW` is possibly ever legitimate, but hey.

Fixes scala/bug#9240
Fixes scala/bug#10361
hrhino added a commit to hrhino/scala that referenced this issue Jun 13, 2017
…ing.

All sorts o' specialness going on here. Unit morphs into a BoxedUnit when
it's in a field, but void when it's the return type of a method, which is
expected. This means, though, that the unboxing method of a Unit-wrapping
value class has the signature `()V`, not `()Lscala/runtime/BoxedUnit`, so
attempting to use its value in the equals method spits out some wonderful
invalid bytecode, instead. Similar sadness occurs for Nothing and Null as
well.

The "solution" is to not even bother to check for equality, as we've only
got at most one legitimate value of each of these types. Because the code
is shared with `case class`es, this also changes the bytecode we generate
for them. Obviously this is an "unrelated change" as far as the bugs this
is meant to fix go, but it's innocuous enough as far as I can tell.

I also slipped a constructor call into the generated `ClassCastException`
that gets thrown when we are asked to emit a cast for a primitive type in
BCodeBodyBuilder, so we generate valid bytecode in that case. I've got no
idea how `NEW; DUP; ATHROW` is possibly ever legitimate, but hey.

Fixes scala/bug#9240
Fixes scala/bug#10361
hrhino added a commit to hrhino/scala that referenced this issue Jun 14, 2017
…ing.

All sorts o' specialness going on here. Unit morphs into a BoxedUnit when
it's in a field, but void when it's the return type of a method, which is
expected. This means, though, that the unboxing method of a Unit-wrapping
value class has the signature `()V`, not `()Lscala/runtime/BoxedUnit`, so
attempting to use its value in the equals method spits out some wonderful
invalid bytecode, instead. Similar sadness occurs for Nothing and Null as
well.

The "solution" is to not even bother to check for equality, as we've only
got at most one legitimate value of each of these types. Because the code
is shared with `case class`es, this also changes the bytecode we generate
for them. Obviously this is an "unrelated change" as far as the bugs this
is meant to fix go, but it's innocuous enough as far as I can tell.

I also slipped a constructor call into the generated `ClassCastException`
that gets thrown when we are asked to emit a cast for a primitive type in
`BCodeBodyBuilder`, so we generate valid bytecode if we ever wind in that
branch. Discussion on scala#5938 implies that this branch shouldn't
ever be reached, so add a devWarning now that it doesn't cause an obvious
error.

Fixes scala/bug#9240
Fixes scala/bug#10361
@SethTisue SethTisue modified the milestones: Backlog, 2.12.3 Oct 26, 2017
xuwei-k added a commit to xuwei-k/scalaz that referenced this issue May 21, 2018
S11001001 added a commit to digital-asset/daml that referenced this issue Sep 3, 2020
mergify bot pushed a commit to digital-asset/daml that referenced this issue Sep 3, 2020
* get a LoggingContext into the TriggerRunnerImpl

* make some implicits more implicitly scoped and explicitly ascribed

* make some private/final markings

* most of JsonFormat[Identifier] is in companion

* experimental LoggingContext with phantom type

* ActorContext#log isn't really doing that much

* more details of LoggingContextOf

* make LoggingContextOf compile

* add trigger message logging, yet without context

* fix parent compile errors

* use Config as the phantom for its own logging extensions

* LocalDateTimeFormat cleanup

* switch TriggerRunner to contextual logging

* add trigger definition ID to logs

* log trigger-submitted commands, fix trigger test compile

* log trigger stopping and DAR uploads

* add context to PostStop/PreRestart logs

* add changelog

CHANGELOG_BEGIN
- [Triggers] More detailed logging of trigger actions and trigger service actions.
  See `issue #7205 <https://github.com/digital-asset/daml/pull/7205>`_.
CHANGELOG_END

* missed copyright header

* switch to Unit, scala/bug#9240 fixed
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

6 participants