diff --git a/pkcs11mod.go b/pkcs11mod.go index 69ffa57..1019556 100644 --- a/pkcs11mod.go +++ b/pkcs11mod.go @@ -94,6 +94,9 @@ func Go_Initialize() C.CK_RV { //export Go_Finalize func Go_Finalize() C.CK_RV { err := backend.Finalize() + + exitSoon() + return fromError(err) } diff --git a/prevent_unload_other.go b/prevent_unload_other.go index 68eee10..8eefb53 100644 --- a/prevent_unload_other.go +++ b/prevent_unload_other.go @@ -6,3 +6,6 @@ package pkcs11mod func preventUnload() { } + +func exitSoon() { +} diff --git a/prevent_unload_windows.go b/prevent_unload_windows.go index d621b22..40af136 100644 --- a/prevent_unload_windows.go +++ b/prevent_unload_windows.go @@ -4,6 +4,9 @@ package pkcs11mod import ( "log" + "os" + "path/filepath" + "time" "golang.org/x/sys/windows" ) @@ -37,3 +40,39 @@ func preventUnload() { log.Println("pkcs11mod: Pinned module") } } + +// This hack prevents a hang if the application tries to wait for all +// background threads to finish before exiting the process. Affected +// applications include Unity and NSS certutil. +// See the following references: +// https://github.com/golang/go/issues/11100#issuecomment-389539527 +// https://github.com/golang/go/issues/11100#issuecomment-487840893 +func exitSoon() { + exePath, err := os.Executable() + if err != nil { + log.Printf("pkcs11mod: Error detecting executable name: %s", err) + return + } + + exe := filepath.Base(exePath) + + shouldForceExitSoon := false + + switch exe { + case "certutil.exe": + shouldForceExitSoon = true + default: + log.Println("pkcs11mod: Unknown exe name '%s'. This is probably fine, but if you see this application hang on exit immediately after this message was logged, consider reporting a bug to pkcs11mod; provide the exe name from this log message.", exe) + } + + if shouldForceExitSoon { + if trace { + log.Println("pkcs11mod: Exiting process soon") + } + + go func() { + time.Sleep(5 * time.Second) + os.Exit(0) + }() + } +}