Skip to content

JVM hard crash in MasterChannel::removePoll #384

@kevinherron

Description

@kevinherron

During some refactor/test cycles I managed to screw up my lifecycle management and cause a full JVM crash.

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGBUS (0xa) at pc=0x00000001372fb608, pid=51369, tid=4611
#
# JRE version: OpenJDK Runtime Environment Zulu17.58+21-CA (17.0.15+6) (build 17.0.15+6-LTS)
# Java VM: OpenJDK 64-Bit Server VM Zulu17.58+21-CA (17.0.15+6-LTS, mixed mode, sharing, tiered, compressed oops, compressed class ptrs, g1 gc, bsd-aarch64)
# Problematic frame:
# C  [libdnp3_ffi_java3084399562012808444.dylib+0x38f608]  tokio::util::rand::rt::RngSeedGenerator::next_seed::hf9158dd50c60d97f+0x1c
#
# No core dump will be written. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /Users/kevin/Development/IA/ignition_83/Modules/driver-dnp3-v2/dnp3-gateway-v2/hs_err_pid51369.log
#
# If you would like to submit a bug report, please visit:
#   http://www.azul.com/support/
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#

I narrowed it down to calling MasterChannel::removePoll after MasterChannel::shutdown.

Even though this is obviously wrong, I think JVM crashes should be considered a critical bug even if it's a result of misusing the library.

It's easily reproducible:

class Dnp3Crash {

    @Test
    fun `removing a PollId after shutdown causes a crash`() {
        val runtime = Runtime(RuntimeConfig())

        val masterChannel = MasterChannel.createTcpChannel(
            runtime,
            LinkErrorMode.CLOSE,
            MasterChannelConfig(ushort(3)),
            EndpointList("localhost:20000"),
            ConnectStrategy(),
            ClientStateListenerImpl
        )

        val associationId = masterChannel.addAssociation(
            ushort(4),
            AssociationConfig(
                EventClasses.all(),
                EventClasses.all(),
                Classes.all(),
                EventClasses.none()
            ),
            object : ReadHandler {},
            AssociationHandlerImpl,
            AssociationInformationImpl
        )

        val pollId: PollId = masterChannel.addPoll(
            associationId,
            Request.classRequest(true, true, true, true),
            60.seconds.toJavaDuration()
        )

        masterChannel.enable()
        masterChannel.disable()
        masterChannel.shutdown()

        masterChannel.removePoll(pollId)
    }

    object ClientStateListenerImpl : ClientStateListener {
        override fun onChange(state: ClientState) {
            println("onChange: $state")
        }
    }

    object AssociationHandlerImpl : AssociationHandler {
        override fun getCurrentTime(): UtcTimestamp {
            return UtcTimestamp.valid(ulong(System.currentTimeMillis()))
        }
    }

    object AssociationInformationImpl : AssociationInformation {
        override fun taskStart(taskType: TaskType?, functionCode: FunctionCode?, seq: UByte?) {
            println("taskStart: $taskType, $functionCode, $seq")
        }

        override fun taskSuccess(taskType: TaskType?, functionCode: FunctionCode?, seq: UByte?) {
            println("taskSuccess: $taskType, $functionCode, $seq")
        }

        override fun taskFail(taskType: TaskType?, error: TaskError?) {
            println("taskFail: $taskType, error=$error")
        }

        override fun unsolicitedResponse(isDuplicate: Boolean, seq: UByte?) {
            println("unsolicitedResponse: isDuplicate=$isDuplicate, seq=$seq")
        }
    }
}

I'm attaching the hs_err_pid.log file as well.

hs_err_pid51369.log

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions