Undeterministic array copy in Scala using jdk10

Viewed 75

I ran tests of my library using jdk10 and they randomly failed in 50% of cases. I extracted very small fragment of code that reproduce the error and run it in the loop counting failures. Failures count is usually about 100k - 700k for 1M trials.

What I discovered until now:

  1. Code works in jdk8 and fails in jdk9 and jdk10
  2. When you change the order of second and third line in addressToBytes method it works
  3. When you inline methods of SomeOutputStream it works
  4. When you disable last level of java optimization: -XX:TieredStopAtLevel=3 it works
  5. When you run this code in debug mode it mostly works.

I use scala 2.12.6 and javac options: -source 1.8 and -target 1.8. The problem occurs on both Windows and Linux.

The basic question is why addressToBytes method does not always return the same result? Sometimes instead of expected array: [4, 10, 10, 10, 10] some part of address is replaced with 0. For example: [4, 10, 10, 10, 0]

Here is the code you can use to reproduce the problem:

import java.io.OutputStream
import java.net.InetSocketAddress

object RaceCondition {

  class SomeOutputStream(val data: Array[Byte], var currentIndex: Int) extends OutputStream {
    override def write(bytes: Array[Byte], off: Int, len: Int): Unit = {
      System.arraycopy(bytes, off, data, currentIndex, len)
      currentIndex += bytes.length
    }

    def write(b: Int): Unit = {
      data.update(currentIndex, b.toByte)
      currentIndex += 1
    }
  }

  def addressToBytes(sAddress: InetSocketAddress): Array[Byte] = {
    val result: Array[Byte] = new Array[Byte](sAddress.getAddress.getAddress.length + 1)
    val writer = new SomeOutputStream(result, 0)
    val addressBytes = sAddress.getAddress.getAddress
    writer.write(addressBytes.length)
    writer.write(addressBytes)
    writer.data
  }

  def main(args: Array[String]): Unit = {
    var i = 0
    val expected = Array[Byte](4, 10, 10, 10, 10)
    val address = new InetSocketAddress("10.10.10.10", 1234)
    var count = 0
    var lastOk = true
    while (i < 1000000) {
      i += 1
      val data = addressToBytes(address)
      if (!data.sameElements(expected)) {
        count += 1
        if(lastOk){
          println(s"\n\nBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD $i\n\n")
        }
        lastOk = false
      } else {
        if(!lastOk){
          println(s"\n\nGOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOD $i\n\n")
        }
        lastOk = true
      }
    }
    println(s"Failures: $count")
  }
}
0 Answers
Related