Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8169634

Launcher termination can crash if the VM could not be shutdown

    Details

    • Type: Bug
    • Status: Open
    • Priority: P3
    • Resolution: Unresolved
    • Affects Version/s: 9
    • Fix Version/s: tbd_major
    • Component/s: tools
    • Labels:

      Description

      gc/g1/logging/TestG1LoggingFailure.java failed with exception java.lang.RuntimeException: 'pure virtual method called' found in stderr

      [17.322s][info][gc] GC(22) Concurrent Cycle 242.132ms
      [17.336s][info][gc] GC(27) Pause Young (G1 Evacuation Pause) 19M->19M(20M) 13.472ms
      ];
       stderr: [
      Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "main"
      pure virtual method called
      terminate called without an active exception
      ]
       exitValue = 1

      java.lang.RuntimeException: 'pure virtual method called' found in stderr

      at jdk.test.lib.process.OutputAnalyzer.shouldNotContain(OutputAnalyzer.java:180)
      at gc.g1.logging.TestG1LoggingFailure.startVM(TestG1LoggingFailure.java:68)
      at gc.g1.logging.TestG1LoggingFailure.main(TestG1LoggingFailure.java:61)
      at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(java.base@9-internal/Native Method)
      at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(java.base@9-internal/NativeMethodAccessorImpl.java:62)
      at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base@9-internal/DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(java.base@9-internal/Method.java:537)
      at com.sun.javatest.regtest.agent.MainWrapper$MainThread.run(MainWrapper.java:110)
      at java.lang.Thread.run(java.base@9-internal/Thread.java:844)
      1. gdb-all-stacks.txt
        121 kB
        Stefan Karlsson
      2. pure.c
        2 kB
        Robbin Ehn
      3. R.java
        4 kB
        Stefan Karlsson
      4. R.java
        2 kB
        Robbin Ehn

        Issue Links

          Activity

          Hide
          dholmes David Holmes added a comment -
          There was a fair amount of discussion about this bug on IM. It obviously seems "wrong" that causing OOME can crash the VM.

          Erik writes:

          To me there are three questions we need to think about with regards to this issue:
          1. Should the Java launcher checks the return code from JNI_DestroyJavaVM? Right now it doesn't. If it should check the return code, what it should the launcher if do if it doesn't get JNI_OK? Calling _exit(2) instead of exit(3)?
          2. Should JNI_DestroyJavaVM be "OOM safe"? This can for example be achieved by pre-allocating a Java Thread object when the JVM starts up
          3. Should the JVM never crash because of a call to exit(3) regardless of its current state? This could be done by for example not using static variables and don't register any exit handlers with on_exit(3)

          The answers to these questions determines if this should be a "test bug" or a normal bug (although a very unlikely bug)

          I responded:

          The test is problematic regardless of how we answer those questions. Unless the VM exits normally the test will fail. So the test needs to be modified to be reliable.

          The launcher should check return codes but what does it do? If it terminates the process then we have a bad outcome regardless if that is a "crash" or otherwise. If the launcher just keeps retrying to JNI_DestroyJavaVM we might hang - but that may be better.

          Making DestroyJavaVM "OOME safe" requires more than simply pre-allocating a Thread object. The attach process can hit the OOME in numerous locations. I think it would take a completely different approach to managing the VM lifecycle to achieve this. Not a short-term fix by any means.

          I'm happy to see a RFE (or bug) filed against the launcher to consider this further, but the test still needs to be modified IMHO.

          Changing the VM to not use at_exit handlers doesn't really help if the launcher will still cause the process to abort/exit abruptly (though we can already do this under native OOM conditions anyway so maybe that isn't so bad?). If the launcher doesn't abort/exit then it doesn't matter if at_exit handlers are used.
          Show
          dholmes David Holmes added a comment - There was a fair amount of discussion about this bug on IM. It obviously seems "wrong" that causing OOME can crash the VM. Erik writes: To me there are three questions we need to think about with regards to this issue: 1. Should the Java launcher checks the return code from JNI_DestroyJavaVM? Right now it doesn't. If it should check the return code, what it should the launcher if do if it doesn't get JNI_OK? Calling _exit(2) instead of exit(3)? 2. Should JNI_DestroyJavaVM be "OOM safe"? This can for example be achieved by pre-allocating a Java Thread object when the JVM starts up 3. Should the JVM never crash because of a call to exit(3) regardless of its current state? This could be done by for example not using static variables and don't register any exit handlers with on_exit(3) The answers to these questions determines if this should be a "test bug" or a normal bug (although a very unlikely bug) I responded: The test is problematic regardless of how we answer those questions. Unless the VM exits normally the test will fail. So the test needs to be modified to be reliable. The launcher should check return codes but what does it do? If it terminates the process then we have a bad outcome regardless if that is a "crash" or otherwise. If the launcher just keeps retrying to JNI_DestroyJavaVM we might hang - but that may be better. Making DestroyJavaVM "OOME safe" requires more than simply pre-allocating a Thread object. The attach process can hit the OOME in numerous locations. I think it would take a completely different approach to managing the VM lifecycle to achieve this. Not a short-term fix by any means. I'm happy to see a RFE (or bug) filed against the launcher to consider this further, but the test still needs to be modified IMHO. Changing the VM to not use at_exit handlers doesn't really help if the launcher will still cause the process to abort/exit abruptly (though we can already do this under native OOM conditions anyway so maybe that isn't so bad?). If the launcher doesn't abort/exit then it doesn't matter if at_exit handlers are used.
          Hide
          dholmes David Holmes added a comment -
          After further discussion on IM it was decided this this bug be moved to tools->launcher to address the problem of how the launcher should deal with a failure of JNI_DestroyJavaVM.

          A subtask will ProblemList the test under this bug ID.
          Show
          dholmes David Holmes added a comment - After further discussion on IM it was decided this this bug be moved to tools->launcher to address the problem of how the launcher should deal with a failure of JNI_DestroyJavaVM. A subtask will ProblemList the test under this bug ID.
          Hide
          mgerdin Mikael Gerdin added a comment -
          One way to fix this from the launcher side could be by utilizing the primordial C thread a bit more:
          1) Invoke JNI_CreateJavaVM from the primordial thread
          2) Spawn a new thread that is intended to become the main thread and attach it to the JVM
          3) The new thread would invoke the java main method
          4) After main returns its C thread would terminate and the primordial thread would wake up
          5) The primordial thread invokes JNI_DestroyJavaVM (but since the primordial thread was implicitly attached by creating the VM there are no allocations
          6) DestroyJavaVM is able to proceed past the critical point and VM shutdown can be performed.
          Show
          mgerdin Mikael Gerdin added a comment - One way to fix this from the launcher side could be by utilizing the primordial C thread a bit more: 1) Invoke JNI_CreateJavaVM from the primordial thread 2) Spawn a new thread that is intended to become the main thread and attach it to the JVM 3) The new thread would invoke the java main method 4) After main returns its C thread would terminate and the primordial thread would wake up 5) The primordial thread invokes JNI_DestroyJavaVM (but since the primordial thread was implicitly attached by creating the VM there are no allocations 6) DestroyJavaVM is able to proceed past the critical point and VM shutdown can be performed.
          Hide
          coleenp Coleen Phillimore added a comment -
          This doesn't need to be fixed in jdk9. It's been a problem since forever.
          Show
          coleenp Coleen Phillimore added a comment - This doesn't need to be fixed in jdk9. It's been a problem since forever.
          Hide
          dholmes David Holmes added a comment -
          Using the primordial thread to attach to the VM is problematic - which is why we create a separate thread in the first place. But the solution is just a small step away: create a third thread just to destroy the VM. The protocol would be:

          - Primordial thread creates main thread, starts it and does a join() to wait for it
          - main thread calls createJavaVM which attaches it to the VM
          - main thread starts destroy thread and waits for it to attach
          - destroy thread tries to attach to VM:
          - - if successful it calls DestroyJavaVM to wait for termination
          - - else it sets an error flag
          - - in both cases it signals the main thread
          - main threads wakes up and checks status of destroy thread
          - - if an error then main threads calls DestroyJavaVM (will destroy VM immediately) and completes
          - - else main thread calls main() method to run the application
          - - when main() returns the main thread joins the destroy thread, then completes

          Of course there is always a trade-off and this will impact startup time
          Show
          dholmes David Holmes added a comment - Using the primordial thread to attach to the VM is problematic - which is why we create a separate thread in the first place. But the solution is just a small step away: create a third thread just to destroy the VM. The protocol would be: - Primordial thread creates main thread, starts it and does a join() to wait for it - main thread calls createJavaVM which attaches it to the VM - main thread starts destroy thread and waits for it to attach - destroy thread tries to attach to VM: - - if successful it calls DestroyJavaVM to wait for termination - - else it sets an error flag - - in both cases it signals the main thread - main threads wakes up and checks status of destroy thread - - if an error then main threads calls DestroyJavaVM (will destroy VM immediately) and completes - - else main thread calls main() method to run the application - - when main() returns the main thread joins the destroy thread, then completes Of course there is always a trade-off and this will impact startup time

            People

            • Assignee:
              ksrini Kumar Srinivasan
              Reporter:
              mchernov Michail Chernov
            • Votes:
              0 Vote for this issue
              Watchers:
              13 Start watching this issue

              Dates

              • Created:
                Updated: