Reproduce and fix ByteString initialization issue (#29244)

* Reproduce ByteString initialization issue

* scalafmt

* make test reliably fail

* core: fix initialization of `ByteString.empty`

Refs #29263

Co-authored-by: Johannes Rudolph <johannes.rudolph@gmail.com>
This commit is contained in:
Arnout Engelen 2020-07-07 15:42:38 +02:00 committed by GitHub
parent 193f4ad704
commit 7f22b9648c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 53 additions and 1 deletions

View file

@ -0,0 +1,52 @@
/*
* Copyright (C) 2020 Lightbend Inc. <https://www.lightbend.com>
*/
package akka.util
import java.io.InputStream
import org.scalatest.matchers.should.Matchers
import org.scalatest.wordspec.AnyWordSpec
import scala.collection.mutable
import scala.collection.mutable.ArrayBuilder
class ByteStringInitializationSpec extends AnyWordSpec with Matchers {
"ByteString intialization" should {
"not get confused by initializing CompactByteString before ByteString" in {
// a classloader that creates a new universe of classes for everything beneath akka
// that prevents that this test interacts with any tests
val cleanCl = new ClassLoader(null) {
val outerCl = ByteStringInitializationSpec.this.getClass.getClassLoader
val buffer = new Array[Byte](1000000)
override def loadClass(name: String): Class[_] =
if (!name.startsWith("akka")) outerCl.loadClass(name)
else {
val classFile = name.replace(".", "/") + ".class"
val is = outerCl.getResourceAsStream(classFile)
val res = slurp(is, new mutable.ArrayBuilder.ofByte)
defineClass(name, res, 0, res.length)
}
def slurp(is: InputStream, res: ArrayBuilder[Byte]): Array[Byte] = {
val read = is.read(buffer)
if (read == 0) throw new IllegalStateException
else if (read > 0) slurp(is, res ++= buffer.take(read))
else res.result()
}
}
import scala.language.reflectiveCalls
type WithRun = { def run(): Unit }
cleanCl.loadClass("akka.util.ByteStringInitTest").newInstance().asInstanceOf[WithRun].run()
}
}
}
class ByteStringInitTest {
def run(): Unit = {
require(CompactByteString.empty ne null)
require(ByteString.empty ne null)
}
}

View file

@ -747,7 +747,7 @@ sealed abstract class ByteString
override protected def fromSpecific(coll: IterableOnce[Byte]): ByteString = ByteString(coll)
override protected def newSpecificBuilder: mutable.Builder[Byte, ByteString] = ByteString.newBuilder
override val empty: ByteString = ByteString.empty
override def empty: ByteString = ByteString.empty
def apply(idx: Int): Byte
private[akka] def byteStringCompanion: ByteString.Companion