changeset 60728:b5fb0d2a1687

8232114: JVM crashed at imjpapi.dll in native code Reviewed-by: serb, alitvinov
author dmarkov
date Wed, 26 Aug 2020 08:13:33 +0100
parents 365b1d53250d
children 5a89be844a76
files src/java.desktop/windows/native/libawt/windows/awt_InputMethod.cpp src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp src/java.desktop/windows/native/libawt/windows/awt_Toolkit.h
diffstat 3 files changed, 74 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.desktop/windows/native/libawt/windows/awt_InputMethod.cpp	Mon Aug 24 22:12:26 2020 +0100
+++ b/src/java.desktop/windows/native/libawt/windows/awt_InputMethod.cpp	Wed Aug 26 08:13:33 2020 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -57,7 +57,7 @@
     TRY;
 
     // use special message to call ImmCreateContext() in main thread.
-    return (jint)AwtToolkit::GetInstance().SendMessage(WM_AWT_CREATECONTEXT);
+    return (jint)AwtToolkit::GetInstance().InvokeInputMethodFunction(WM_AWT_CREATECONTEXT);
 
     CATCH_BAD_ALLOC_RET(0);
 }
@@ -74,7 +74,7 @@
     TRY_NO_VERIFY;
 
     // use special message to call ImmDestroyContext() in main thread.
-    AwtToolkit::GetInstance().SendMessage(WM_AWT_DESTROYCONTEXT, context, 0);
+    AwtToolkit::GetInstance().InvokeInputMethodFunction(WM_AWT_DESTROYCONTEXT, context, 0);
 
     CATCH_BAD_ALLOC;
 }
@@ -101,7 +101,7 @@
     enis->context = context;
     enis->useNativeCompWindow = useNativeCompWindow;
 
-    AwtToolkit::GetInstance().SendMessage(WM_AWT_ASSOCIATECONTEXT,
+    AwtToolkit::GetInstance().InvokeInputMethodFunction(WM_AWT_ASSOCIATECONTEXT,
                                           reinterpret_cast<WPARAM>(enis), (LPARAM)0);
     // global refs are deleted in message handler
 
@@ -128,7 +128,7 @@
     enis->context = NULL;
     enis->useNativeCompWindow = JNI_TRUE;
 
-    AwtToolkit::GetInstance().SendMessage(WM_AWT_ASSOCIATECONTEXT,
+    AwtToolkit::GetInstance().InvokeInputMethodFunction(WM_AWT_ASSOCIATECONTEXT,
                                           reinterpret_cast<WPARAM>(enis), (LPARAM)0);
     // global refs are deleted in message handler
 
@@ -205,7 +205,7 @@
     // 10/29/98 - Changed to commit it according to the flag.
 
     // use special message to call ImmNotifyIME() in main thread.
-    AwtToolkit::GetInstance().SendMessage(WM_AWT_ENDCOMPOSITION, context,
+    AwtToolkit::GetInstance().InvokeInputMethodFunction(WM_AWT_ENDCOMPOSITION, context,
         (LPARAM)(flag != sun_awt_windows_WInputMethod_DISCARD_INPUT));
 
     CATCH_BAD_ALLOC;
@@ -222,7 +222,7 @@
     TRY;
 
     // use special message to call ImmSetConversionStatus() in main thread.
-    AwtToolkit::GetInstance().SendMessage(WM_AWT_SETCONVERSIONSTATUS,
+    AwtToolkit::GetInstance().InvokeInputMethodFunction(WM_AWT_SETCONVERSIONSTATUS,
                                           context,
                                           MAKELPARAM((WORD)request, (WORD)0));
 
@@ -240,7 +240,7 @@
     TRY;
 
     // use special message to call ImmSetConversionStatus() in main thread.
-    return (jint) AwtToolkit::GetInstance().SendMessage(
+    return (jint) AwtToolkit::GetInstance().InvokeInputMethodFunction(
         WM_AWT_GETCONVERSIONSTATUS, context, 0);
 
     CATCH_BAD_ALLOC_RET(0);
@@ -257,7 +257,7 @@
     TRY;
 
     // use special message to call ImmSetConversionStatus() in main thread.
-    AwtToolkit::GetInstance().SendMessage(WM_AWT_SETOPENSTATUS,
+    AwtToolkit::GetInstance().InvokeInputMethodFunction(WM_AWT_SETOPENSTATUS,
                                           context, flag);
 
     CATCH_BAD_ALLOC;
@@ -274,7 +274,7 @@
     TRY;
 
     // use special message to call ImmSetConversionStatus() in main thread.
-    return (jboolean)(AwtToolkit::GetInstance().SendMessage(
+    return (jboolean)(AwtToolkit::GetInstance().InvokeInputMethodFunction(
                                                        WM_AWT_GETOPENSTATUS,
                                                        context, 0));
     CATCH_BAD_ALLOC_RET(0);
@@ -392,7 +392,7 @@
         jobject peerGlobalRef = env->NewGlobalRef(peer);
 
         // use special message to access pData on the toolkit thread
-        LRESULT res = AwtToolkit::GetInstance().SendMessage(WM_AWT_GET_DEFAULT_IME_HANDLER,
+        LRESULT res = AwtToolkit::GetInstance().InvokeInputMethodFunction(WM_AWT_GET_DEFAULT_IME_HANDLER,
                                           reinterpret_cast<WPARAM>(peerGlobalRef), 0);
         // global ref is deleted in message handler
 
@@ -431,7 +431,7 @@
     // See CR 4805862, AwtToolkit::WndProc
 
     // use special message to open candidate window in main thread.
-    AwtToolkit::GetInstance().SendMessage(WM_AWT_OPENCANDIDATEWINDOW,
+    AwtToolkit::GetInstance().InvokeInputMethodFunction(WM_AWT_OPENCANDIDATEWINDOW,
                                           (WPARAM)peerGlobalRef, MAKELONG(x, y));
     // global ref is deleted in message handler
 
--- a/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp	Mon Aug 24 22:12:26 2020 +0100
+++ b/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp	Wed Aug 26 08:13:33 2020 +0100
@@ -343,6 +343,7 @@
     ::GetKeyboardState(m_lastKeyboardState);
 
     m_waitEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
+    m_inputMethodWaitEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
     isInDoDragDropLoop = FALSE;
     eventNumber = 0;
 }
@@ -777,6 +778,7 @@
     delete tk.m_cmdIDs;
 
     ::CloseHandle(m_waitEvent);
+    ::CloseHandle(m_inputMethodWaitEvent);
 
     tk.m_isDisposed = TRUE;
 
@@ -1087,11 +1089,17 @@
       // it returs with no error. (This restriction is not documented)
       // So we must use thse messages to call these APIs in main thread.
       case WM_AWT_CREATECONTEXT: {
-        return reinterpret_cast<LRESULT>(
+          AwtToolkit& tk = AwtToolkit::GetInstance();
+          tk.m_inputMethodData = reinterpret_cast<LRESULT>(
             reinterpret_cast<void*>(ImmCreateContext()));
+          ::SetEvent(tk.m_inputMethodWaitEvent);
+          return tk.m_inputMethodData;
       }
       case WM_AWT_DESTROYCONTEXT: {
           ImmDestroyContext((HIMC)wParam);
+          AwtToolkit& tk = AwtToolkit::GetInstance();
+          tk.m_inputMethodData = 0;
+          ::SetEvent(tk.m_inputMethodWaitEvent);
           return 0;
       }
       case WM_AWT_ASSOCIATECONTEXT: {
@@ -1117,17 +1125,21 @@
           }
 
           delete data;
+          AwtToolkit& tk = AwtToolkit::GetInstance();
+          tk.m_inputMethodData = 0;
+          ::SetEvent(tk.m_inputMethodWaitEvent);
           return 0;
       }
       case WM_AWT_GET_DEFAULT_IME_HANDLER: {
           LRESULT ret = (LRESULT)FALSE;
           jobject peer = (jobject)wParam;
+          AwtToolkit& tk = AwtToolkit::GetInstance();
 
           AwtComponent* comp = (AwtComponent*)JNI_GET_PDATA(peer);
           if (comp != NULL) {
               HWND defaultIMEHandler = ImmGetDefaultIMEWnd(comp->GetHWnd());
               if (defaultIMEHandler != NULL) {
-                  AwtToolkit::GetInstance().SetInputMethodWindow(defaultIMEHandler);
+                  tk.SetInputMethodWindow(defaultIMEHandler);
                   ret = (LRESULT)TRUE;
               }
           }
@@ -1135,6 +1147,8 @@
           if (peer != NULL) {
               env->DeleteGlobalRef(peer);
           }
+          tk.m_inputMethodData = ret;
+          ::SetEvent(tk.m_inputMethodWaitEvent);
           return ret;
       }
       case WM_AWT_HANDLE_NATIVE_IME_EVENT: {
@@ -1170,6 +1184,9 @@
           Changed to commit it according to the flag 10/29/98*/
           ImmNotifyIME((HIMC)wParam, NI_COMPOSITIONSTR,
                        (lParam ? CPS_COMPLETE : CPS_CANCEL), 0);
+          AwtToolkit& tk = AwtToolkit::GetInstance();
+          tk.m_inputMethodData = 0;
+          ::SetEvent(tk.m_inputMethodWaitEvent);
           return 0;
       }
       case WM_AWT_SETCONVERSIONSTATUS: {
@@ -1177,12 +1194,18 @@
           DWORD smode;
           ImmGetConversionStatus((HIMC)wParam, (LPDWORD)&cmode, (LPDWORD)&smode);
           ImmSetConversionStatus((HIMC)wParam, (DWORD)LOWORD(lParam), smode);
+          AwtToolkit& tk = AwtToolkit::GetInstance();
+          tk.m_inputMethodData = 0;
+          ::SetEvent(tk.m_inputMethodWaitEvent);
           return 0;
       }
       case WM_AWT_GETCONVERSIONSTATUS: {
           DWORD cmode;
           DWORD smode;
           ImmGetConversionStatus((HIMC)wParam, (LPDWORD)&cmode, (LPDWORD)&smode);
+          AwtToolkit& tk = AwtToolkit::GetInstance();
+          tk.m_inputMethodData = cmode;
+          ::SetEvent(tk.m_inputMethodWaitEvent);
           return cmode;
       }
       case WM_AWT_ACTIVATEKEYBOARDLAYOUT: {
@@ -1217,6 +1240,9 @@
           // instead of LOWORD and HIWORD
           p->OpenCandidateWindow(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
           env->DeleteGlobalRef(peerObject);
+          AwtToolkit& tk = AwtToolkit::GetInstance();
+          tk.m_inputMethodData = 0;
+          ::SetEvent(tk.m_inputMethodWaitEvent);
           return 0;
       }
 
@@ -1238,10 +1264,16 @@
 
       case WM_AWT_SETOPENSTATUS: {
           ImmSetOpenStatus((HIMC)wParam, (BOOL)lParam);
+          AwtToolkit& tk = AwtToolkit::GetInstance();
+          tk.m_inputMethodData = 0;
+          ::SetEvent(tk.m_inputMethodWaitEvent);
           return 0;
       }
       case WM_AWT_GETOPENSTATUS: {
-          return (DWORD)ImmGetOpenStatus((HIMC)wParam);
+          AwtToolkit& tk = AwtToolkit::GetInstance();
+          tk.m_inputMethodData = (DWORD)ImmGetOpenStatus((HIMC)wParam);
+          ::SetEvent(tk.m_inputMethodWaitEvent);
+          return tk.m_inputMethodData;
       }
       case WM_DISPLAYCHANGE: {
           // Reinitialize screens
@@ -3166,3 +3198,23 @@
     }
     return m_pCloseTouchInputHandle(hTouchInput);
 }
+
+/*
+ * The fuction intended for access to an IME API. It posts IME message to the queue and
+ * waits untill the message processing is completed.
+ *
+ * On Windows 10 the IME may process the messages send via SenMessage() from other threads
+ * when the IME is called by TranslateMessage(). This may cause an reentrancy issue when
+ * the windows procedure processing the sent message call an IME function and leaves
+ * the IME functionality in an unexpected state.
+ * This function avoids reentrancy issue and must be used for sending of all IME messages
+ * instead of SendMessage().
+ */
+LRESULT AwtToolkit::InvokeInputMethodFunction(UINT msg, WPARAM wParam, LPARAM lParam) {
+    CriticalSection::Lock lock(m_inputMethodLock);
+    if (PostMessage(msg, wParam, lParam)) {
+        ::WaitForSingleObject(m_inputMethodWaitEvent, INFINITE);
+        return m_inputMethodData;
+    }
+    return 0;
+}
--- a/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.h	Mon Aug 24 22:12:26 2020 +0100
+++ b/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.h	Wed Aug 26 08:13:33 2020 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -244,6 +244,8 @@
         UINT cInputs, PTOUCHINPUT pInputs, int cbSize);
     BOOL TICloseTouchInputHandle(HTOUCHINPUT hTouchInput);
 
+    LRESULT InvokeInputMethodFunction(UINT msg, WPARAM wParam=0, LPARAM lParam=0);
+
     INLINE BOOL localPump() { return m_localPump; }
     INLINE BOOL VerifyComponents() { return FALSE; } // TODO: Use new DebugHelper class to set this flag
     INLINE HWND GetHWnd() { return m_toolkitHWnd; }
@@ -498,6 +500,10 @@
     HMODULE m_dllHandle;  /* The module handle. */
 
     CriticalSection m_Sync;
+    CriticalSection m_inputMethodLock;
+
+    HANDLE m_inputMethodWaitEvent;
+    LRESULT m_inputMethodData;
 
 /* track display changes - used by palette-updating code.
    This is a workaround for a windows bug that prevents