Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JVM hangs on exit

I am working on a small app that should sign documents using digital signature and quit. The signature can be in a PKCS#12 archive (.pfx file) or on a smartcard device.

Working with the pfx file is easy and working fine.

However, sometimes using the smartcard device, the process hangs on Windows 8 PCs.

The document is signed correctly, but the process doesn't terminate. It just hangs.

I'm using the Sun's PKCS#11 provider - sun.security.pkcs11.SunPKCS11

Basically I'm doing this:

SunPKCS11 provider = new SunPKCS11(configuration);
Security.addProvider(provider);

..... some work .....

provider.logout()
Security.removeProvider(provider);

Now... even if I call System.exit(0) or throw an exception at the end of the main method, I can see the stacktrace in the output but the process doesn't terminate.

I've added a shutdown hook to see if it is executed and it is, i.e. the JVM is trying to stop.

The hang occures rarely, only on Windows 8 PCs. Tried with different smartcards and it happens only with cards that use cmp11.dll (dlls are provided from the vendors of the smartcards).

Using the same dll for communication with the smartcard, however, works fine on Windows 7, XP or some Windows 8 PCs

Running it with Java 8, Update 45, on either x86 or x64 Windows 8

Tried to get a thread dump to see what is hanging:

public static void main(String[] args) {
  // do my job, register provider, sign documents, remove provider ...

  for(int i = 0; i < 20; ++i) {
    System.err.println("Sleep... " + i);
    Thread.sleep(2 * 1000);
  }
  System.err.println("Exiting...");
}

If I execute jstack -l 3232 > dump.log 2>&1 when Sleep... x is printing, everything looks OK.

However, if I execute jstack -F -l 3232 > dump2.log 2>&1 when Exiting... is printed and the app hangs (using -F because the process hangs), i got the following:

Attaching to process ID 3232, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.45-b02
Deadlock Detection:

No deadlocks found.

Thread Exception in thread "main"         
java.lang.reflect.InvocationTargetException
      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:497)
      at sun.tools.jstack.JStack.runJStackTool(JStack.java:140)
      at sun.tools.jstack.JStack.main(JStack.java:106)
Caused by: sun.jvm.hotspot.debugger.DebuggerException: Windbg Error: GetThreadIdBySystemId failed!
      at sun.jvm.hotspot.debugger.windbg.WindbgDebuggerLocal.getThreadIdFromSysId0(Native Method)
      at sun.jvm.hotspot.debugger.windbg.WindbgDebuggerLocal.getThreadIdFromSysId(WindbgDebuggerLocal.java:284)
      at sun.jvm.hotspot.debugger.windbg.amd64.WindbgAMD64Thread.getThreadID(WindbgAMD64Thread.java:88)
      at sun.jvm.hotspot.debugger.windbg.amd64.WindbgAMD64Thread.toString(WindbgAMD64Thread.java:81)
      at java.lang.String.valueOf(String.java:2982)
      at java.io.PrintStream.print(PrintStream.java:683)
      at sun.jvm.hotspot.runtime.win32_amd64.Win32AMD64JavaThreadPDAccess.printThreadIDOn(Win32AMD64JavaThreadPDAccess.java:114)
      at sun.jvm.hotspot.runtime.JavaThread.printThreadIDOn(JavaThread.java:265)
      at sun.jvm.hotspot.tools.StackTrace.run(StackTrace.java:79)
      at sun.jvm.hotspot.tools.StackTrace.run(StackTrace.java:45)
      at sun.jvm.hotspot.tools.JStack.run(JStack.java:66)
      at sun.jvm.hotspot.tools.Tool.startInternal(Tool.java:260)
      at sun.jvm.hotspot.tools.Tool.start(Tool.java:223)
      at sun.jvm.hotspot.tools.Tool.execute(Tool.java:118)
      at sun.jvm.hotspot.tools.JStack.main(JStack.java:92)
      ... 6 more

I can see the process with PID 3232 in the task manager!

Any idea why it is not terminating or why jstack fails?

EDIT


Ok, tried to extract the signing in a separate process, execute it with Runtime.exec and then kill it with Process.destroy but... doesn't seem to help. The child process still stays in the task manager.

Aaaaand... now I have no other choice but to make it kill itself ;(

try {
  String name = java.lang.management.ManagementFactory.getRuntimeMXBean().getName();
  Runtime.getRuntime().exec("taskkill.exe /F /PID " + name.split("@")[0]);
}
catch(Throwable t) {
  Runtime.getRuntime().exec("taskkill.exe /F /IM java.exe"); 
}

EDIT 2


Tried with Runtime.halt as well. Still doesn't terminate the process...

I would appreciate any ideas!

like image 203
Ivan Nikolchov Avatar asked Jun 18 '15 09:06

Ivan Nikolchov


2 Answers

This won't address your root cause, but this method can be used to force the JVM to terminate:

http://docs.oracle.com/javase/7/docs/api/java/lang/Runtime.html#halt(int)

As the Javadoc says, use with extreme caution ;-)

like image 56
Firefly Avatar answered Oct 05 '22 22:10

Firefly


I have some problem with sun.security.pkcs11.SunPKCS11 on Windows 8 PCs.This is working for me:

Runtime.getRuntime().exec("taskkill.exe /F /PID " + name.split("@")[0]);
Thread.sleep(500);
like image 43
Venko Stefanov Avatar answered Oct 06 '22 00:10

Venko Stefanov