UnityEngine.Input freezes on WSA input text box when typing rapidly or often randomly

We’re experiencing a blocker bug on the WSA platform. We’re using the old UnityEngine.Input API and not the newer UnityEngine.InputSystem API. This blocker issue does not appear in 2019.4.12f1. But it does manifest in 2019.4.19f. An upgrade to 2019.f.22f did not fix the issue. It appears the bug was introduced fairly recently. The bug is very, very easy to reproduce.

After typing rapidly into an Input text box or frequently just typing normally, the system freezes. I’ve run this in the VS 2019 debugger and narrowed down the root cause to a multi-threaded deadlock.

This issue reproduces consistently in our project. However I’ve reproduced the bug using Unity’s sample input text example.

public class InputProxy : MonoBehaviour
{
[SerializeField] private InputField Text;
// Start is called before the first frame update
void Start()
{
Keyboard.current.onTextInput += (char character) =>
{
Debug.Log($“Key pressed {character}”);
Text.text += character;
};
}
}

Thread A is deadlocked waiting for Thread B

Thread A (Waiting on lock owned by Thread B)

[Waiting on lock owned by Thread 35064, double-click or press enter to switch to thread]
ntdll.dll!NtWaitForAlertByThreadId()
ntdll.dll!RtlpWaitOnAddressWithTimeout()
ntdll.dll!RtlpWaitOnAddress()
ntdll.dll!RtlpWaitOnCriticalSection()
ntdll.dll!RtlpEnterCriticalSectionContended()
ntdll.dll!RtlEnterCriticalSection()
TextInputFramework.dll!CTextInputClientFreeThread::EditControlInfoChanged()
msctf.dll!CTextInputClientOwnerAdapter::EditControlInfoChanged()
msctf.dll!CTextInputClientWrapper::EditControlInfoChanged()
Windows.UI.Core.TextInput.dll!Windows::UI::Text::Core::CEditContext::put_IsReadOnly()
UnityPlayer.dll!winrt::impl::consume_Windows_UI_Text_Core_ICoreTextEditContext<struct winrt::Windows::UI::Text::Core::ICoreTextEditContext>::IsReadOnly(bool)
UnityPlayer.dll!uwp::ui::TextInputController::AcquireFocus(struct uwp::ui::TextBoxConfigration const &,class core::basic_string<wchar_t,class core::StringStorageDefault<wchar_t> > const &)
UnityPlayer.dll!uwp::ui::TextInputController::AcquireFocus(void)
UnityPlayer.dll!KeyboardOnScreenCoreTextEdit::SetActive(bool)
UnityPlayer.dll!KeyboardOnScreen::SetActive(bool)
UnityPlayer.dll!KeyboardOnScreen::SetText(class core::basic_string<char,class core::StringStorageDefault<char> >)
UnityPlayer.dll!TouchScreenKeyboard_Set_Custom_PropText(class ScriptingBackendNativeObjectPtrOpaque *,class ScriptingBackendNativeStringPtrOpaque *)
GameAssembly.dll!TouchScreenKeyboard_set_text_mF72A794EEC3FC19A9701B61A70BCF392D53B0D38(TouchScreenKeyboard_t2A69F85698E9780470181532D3F2BC903623FD90 * __this, String_t * ___value0, const MethodInfo * method) Line 29197
GameAssembly.dll!InputField_SetText_mEF14F85B3A852C7BB42625B5982DB4BFEBAF313F(InputField_t533609195B110760BCFF00B746C87D81969CB005 * __this, String_t * ___value0, bool ___sendCallback1, const MethodInfo * method) Line 33778
GameAssembly.dll!InputField_set_text_m281F692E6AC99F9AE94EFE140B8AB2AAB5C4ED19(InputField_t533609195B110760BCFF00B746C87D81969CB005 * __this, String_t * ___value0, const MethodInfo * method) Line 33454
GameAssembly.dll!InputProxy_U3CStartU3Eb__1_0_m04CF619389578C9F2C8DFE7994E9B1B5191FFBD2(InputProxy_t9622125E0A01B44A5C9E9079D2930D30F22E80A2 * __this, wchar_t ___character0, const MethodInfo * method) Line 3477
GameAssembly.dll!Action_1_Invoke_mC9191252CB273FF4B1E6BC7732B51B87755CF076_gshared(Action_1_t49CEE65271E77B0724B9809B1517C3095C59B004 * __this, wchar_t ___obj0, const MethodInfo * method) Line 21251
GameAssembly.dll!Action_1_Invoke_mC9191252CB273FF4B1E6BC7732B51B87755CF076(Action_1_t49CEE65271E77B0724B9809B1517C3095C59B004 * __this, wchar_t ___obj0, const MethodInfo * method) Line 18836
GameAssembly.dll!Keyboard_OnTextInput_mEAFCEFAF93966D07C0B5B90DEA8BEA84FA1EAE31(Keyboard_t32E5860C0A34C72A5FDD4B83D506C75CBF00F17C * __this, wchar_t ___character0, const MethodInfo * method) Line 34177
GameAssembly.dll!InterfaceActionInvoker1<wchar_t>::Invoke(unsigned int slot, Il2CppClass * declaringInterface, Il2CppObject * obj, wchar_t p1) Line 106
GameAssembly.dll!InputManager_OnUpdate_mCD0602D473BA35536EDBA570C2A76D1205A9867E(InputManager_tE2A938B45D056C780012C228D64A557963C98CBA * __this, int ___updateType0, InputEventBuffer_t368F34E2F1C4A605D6E9050EEC18C62767ABB448 * ___eventBuffer1, const MethodInfo * method) Line 40465
GameAssembly.dll!InputUpdateDelegate_Invoke_m7B31A33936860E7B3D11B83AA16E7D8A4D84FE85(InputUpdateDelegate_tD572CA50F8F785132B7B88ACCAB64A0E3C37F54A * __this, int ___updateType0, InputEventBuffer_t368F34E2F1C4A605D6E9050EEC18C62767ABB448 * ___eventBuffer1, const MethodInfo * method) Line 31307
GameAssembly.dll!U3CU3Ec__DisplayClass7_0_U3Cset_onUpdateU3Eb__0_mDE54F0ACA6A4DD6364550B941EF1A6B6E76C0BDB(U3CU3Ec__DisplayClass7_0_t1E73E3FC24A2D765A236DC14923AB070DEB33806 * __this, int ___updateType0, NativeInputEventBuffer_t9960648276F01C5C3435E0E6FD870F2DA8A132EF * ___eventBufferPtr1, const MethodInfo * method) Line 32578
GameAssembly.dll!NativeUpdateCallback_Invoke_m0F3B8F934AB1C953397B0E2134D17A9AAEBD975E(NativeUpdateCallback_tCC4B5A2692C21C00FC2FC1E4EC5280E98423B8D5 * __this, int ___updateType0, NativeInputEventBuffer_t9960648276F01C5C3435E0E6FD870F2DA8A132EF * ___buffer1, const MethodInfo * method) Line 1517
GameAssembly.dll!NativeInputSystem_NotifyUpdate_m9AAC791622BA97DC7807610DD08C54F6011834F2(int ___updateType0, __int64 ___eventBuffer1, const MethodInfo * method) Line 1240
GameAssembly.dll!RuntimeInvoker_FalseVoid_t22962CB4C05B1D89B55A6E1139F0E87A90987017_Int32_t585191389E07734F19F3156FF88FB3EF4800D102_IntPtr_t(void(*)() methodPointer, const MethodInfo * methodMetadata, void * obj, void * * args) Line 51329
GameAssembly.dll!il2cpp::vm::Runtime::Invoke(const MethodInfo * method, void * obj, void * * params, Il2CppException * * exc) Line 545
GameAssembly.dll!il2cpp_runtime_invoke(const MethodInfo * method, void * obj, void * * params, Il2CppException * * exc) Line 1075
UnityPlayer.dll!scripting_method_invoke(class ScriptingMethodPtr,class ScriptingObjectPtr,struct ScriptingArguments &,class ScriptingExceptionPtr *,bool)
UnityPlayer.dll!ScriptingInvocation::Invoke(class ScriptingExceptionPtr *,bool)
UnityPlayer.dll!ScriptingInvocation::Invoke<void>(class ScriptingExceptionPtr *,bool)
UnityPlayer.dll!Scripting::UnityEngineInternal::Input::NativeInputSystemProxy::NotifyUpdate(int,void *,class ScriptingExceptionPtr *)
UnityPlayer.dll!SendInputEventsToScript()
UnityPlayer.dll!InputUpdate(enum InputUpdateType)
UnityPlayer.dll!`InternalInitializeModule_Input'::`2'::PreUpdateNewInputUpdateRegistrator::Forward()
UnityPlayer.dll!ExecutePlayerLoop(struct NativePlayerLoopSystem *)
UnityPlayer.dll!ExecutePlayerLoop(struct NativePlayerLoopSystem *)
UnityPlayer.dll!PlayerLoop(void)
UnityPlayer.dll!metro::MainLoop(bool)
UnityPlayer.dll!UnityPlayer::AppCallbacks::smile:oPerformUpdateAndRender(void)
UnityPlayer.dll!UnityPlayer::AppCallbacks::PerformUpdateAndRender(void)
UnityPlayer.dll!UnityPlayer::AppCallbacks::_AppThreadImplementation(void *)
UnityPlayer.dll!UnityPlayer::AppCallbacks::_AppThread(void *)
kernel32.dll!BaseThreadInitThunk()
ntdll.dll!RtlUserThreadStart()```

Thread B (This thread is waiting on a Mutex.)

```Not Flagged 35064 0 Worker Thread SHCore.dll!_WrapperThreadProc UnityPlayer.dll!PlatformMutex::Lock
ntdll.dll!NtWaitForAlertByThreadId()
ntdll.dll!RtlpWaitOnAddressWithTimeout()
ntdll.dll!RtlpWaitOnAddress()
ntdll.dll!RtlpWaitOnCriticalSection()
ntdll.dll!RtlpEnterCriticalSectionContended()
ntdll.dll!RtlEnterCriticalSection()
UnityPlayer.dll!PlatformMutex::Lock(void)
UnityPlayer.dll!Mutex::Lock(void)
UnityPlayer.dll!uwp::ui::TextInputController::OnTextUpdating(struct winrt::Windows::UI::Text::Core::CoreTextTextUpdatingEventArgs const &)
UnityPlayer.dll!winrt::impl::delegate<winrt::Windows::Foundation::TypedEventHandler<winrt::Windows::UI::Text::Core::CoreTextEditContext,winrt::Windows::UI::Text::Core::CoreTextTextUpdatingEventArgs>>::type<<lambda_6e32edd81866d08b092fb0d7968952f0>>::Invoke()
Windows.UI.Core.TextInput.dll!Microsoft::WRL::InvokeTraits<-2>::InvokeDelegates<class <lambda_08d20749b81716ef718bb13b141c8993>,struct Windows::Foundation::ITypedEventHandler<class Windows::UI::ViewManagement::Core::CoreInputView *,class Windows::UI::Internal::ViewManagement::Core::FrameworkInputViewOcclusionsChangedEventArgs *> >(class <lambda_08d20749b81716ef718bb13b141c8993>,class Microsoft::WRL::smile:etails::EventTargetArray *,class Microsoft::WRL::EventSource<struct Windows::Foundation::ITypedEventHandler<class Windows::UI::ViewManagement::Core::CoreInputView *,class Windows::UI::Internal::ViewManagement::Core::FrameworkInputViewOcclusionsChangedEventArgs *>,struct Microsoft::WRL::InvokeModeOptions<-2> > *)
Windows.UI.Core.TextInput.dll!Microsoft::WRL::EventSource<struct Windows::Foundation::ITypedEventHandler<class Windows::UI::ViewManagement::Core::CoreInputView *,class Windows::UI::Internal::ViewManagement::Core::FrameworkInputViewOcclusionsChangedEventArgs *>,struct Microsoft::WRL::InvokeModeOptions<-2> >::smile:oInvoke<class <lambda_08d20749b81716ef718bb13b141c8993> >(class <lambda_08d20749b81716ef718bb13b141c8993>)
Windows.UI.Core.TextInput.dll!Windows::UI::Text::Core::CEditContext::ReplaceTextInternal(int,int,struct MsgString *,bool,int,int)
Windows.UI.Core.TextInput.dll!Windows::UI::Text::Core::CEditContext::ReplaceText(int,int,struct MsgString *)
Windows.UI.Core.TextInput.dll!Windows::UI::Text::Core::CEditContext::InsertText(int,struct MsgString *)
msctf.dll!CTextChange::Execute()
msctf.dll!CTextInputClientOwnerAdapter::_ExecuteOperation()
msctf.dll!CTextInputClientOwnerAdapter::ReplaceText(int,int,struct MsgString *)
TextInputFramework.dll!CTextInputClientOwnerAsync::ReplaceTextInternal(int,int,struct MsgString *,bool,int,int)
TextInputFramework.dll!TextInputClient::ReplaceTextInternal(struct tagMsgRoutingInfo,unsigned int,unsigned int,int,int,struct MsgString *,bool,int,int)
TextInputFramework.dll!TextInputClient::ReplaceText(struct tagMsgRoutingInfo,unsigned int,unsigned int,int,int,struct MsgString *)
TextInputFramework.dll!CTextInputClientFreeThread::ReplaceText()
TextInputFramework.dll!TextInputClientAdapter::ReplaceText(struct tagMsgRoutingInfo,unsigned int,unsigned int,int,int,struct MsgString *)
CoreUIComponents.dll!IRemoteTextInputClient$X__CallbackAdapter::ReplaceTextW(struct Microsoft::CoreUI::MessagingInterop::RoutingInfo,unsigned int,unsigned int,int,int,class System::String *)
CoreUIComponents.dll!IRemoteTextInputClient$X__CallbackAdapter$R::IRemoteTextInputClient_Impl::ReplaceTextW(class System::Object *,struct Microsoft::CoreUI::MessagingInterop::RoutingInfo,unsigned int,unsigned int,int,int,class System::String *)
CoreUIComponents.dll!IRemoteTextInputClient::ReplaceTextW(struct Microsoft::CoreUI::MessagingInterop::RoutingInfo,unsigned int,unsigned int,int,int,class System::String *)
CoreUIComponents.dll!IRemoteTextInputClient$R::Reflection__ReplaceText(void *,void * *,void * *)
CoreUIComponents.dll!Microsoft::CoreUI::Formatting::CnSerializeRead::InvokeMember()
CoreUIComponents.dll!Microsoft::CoreUI::Proxy::ExternalRegisteredObject::Callback_OnMessage()
CoreUIComponents.dll!Microsoft::CoreUI::MessagingInterop::MessageEndpoint$R::smile:elegate1(class System::smile:elegate *,void *,int)
CoreUIComponents.dll!Microsoft__CoreUI__MessagingInterop__EndpointHandler$ExportThunk()
CoreMessaging.dll!Microsoft__CoreUI__ExportEndpointHandler$CallbackThunk(class System::smile:elegate *,void *,int)
CoreMessaging.dll!Microsoft::CoreUI::ExternalEndpoint::Callback_OnMessageCore()
CoreMessaging.dll!Microsoft::CoreUI::Messaging::MessageSessionCommon::Callback_DeliverMessage()
CoreMessaging.dll!Microsoft::CoreUI::Messaging::MessageSessionCommon::Callback_DeliverMessageBatch()
CoreMessaging.dll!Microsoft::CoreUI::Messaging::CrossProcessReceivePort__AlpcReceiveSource::Callback_ProcessBuffer()
CoreMessaging.dll!Microsoft::CoreUI::Messaging::AlpcServerThunk::Callback_ProcessAsynchronousBuffer(struct IAlpcConnection *,void *,unsigned long,void const *,int)
CoreMessaging.dll!AlpcConnection::Callback_DeliverBatchedBuffers()
CoreMessaging.dll!AlpcConnection::HandleSubsequentBufferInBatch()
CoreMessaging.dll!AlpcConnection::Callback_HandleReceivedBuffer()
CoreMessaging.dll!AlpcConnection::Callback_ProcessIncoming()
CoreMessaging.dll!Microsoft::CoreUI::Messaging::CrossProcessReceivePort__AlpcReceiveSource::OnReceive()
CoreMessaging.dll!Microsoft::CoreUI::smile:ispatch::OffThreadReceiver::Callback_OnDispatch()
CoreMessaging.dll!Microsoft::CoreUI::smile:ispatch::EventLoop::Callback_RunCoreLoop()
CoreMessaging.dll!Microsoft::CoreUI::smile:ispatch::UserAdapter::OnUserDispatch()
CoreMessaging.dll!Microsoft::CoreUI::smile:ispatch::UserAdapter_DoWork()
CoreMessaging.dll!Microsoft::CoreUI::smile:ispatch::UserAdapter_WindowProc()
user32.dll!UserCallWinProcCheckWow()
user32.dll!DispatchMessageWorker()
Windows.UI.dll!Windows::UI::Core::CDispatcher::ProcessMessage(bool bDrainQueue, bool * pbWindowMessagesProcessed, bool * pbInvokeItemProcessed) Line 320
Windows.UI.dll!Windows::UI::Core::CDispatcher::WaitAndProcessMessagesInternal(bool bRunAlwaysOnce, void * hEventWait) Line 1950
Windows.UI.dll!Windows::UI::Core::CDispatcher::ProcessEvents(Windows::UI::Core::CoreProcessEventsOption options) Line 596
UnityPlayer.dll!UnityPlayer::AppCallbacks::[UnityPlayer::__IAppCallbacksPublicNonVirtuals]::Run(void)
UnityPlayer.dll!UnityPlayer::AppCallbacks::[UnityPlayer::__IAppCallbacksPublicNonVirtuals]::__abi_UnityPlayer___IAppCallbacksPublicNonVirtuals____abi_Run(void)
inputtestNew.exe!UnityPlayer::__IAppCallbacksPublicNonVirtuals::Run()
inputtestNew.exe!inputtestNew::App::[Windows::ApplicationModel::Core::IFrameworkView]::Run() Line 39
inputtestNew.exe!inputtestNew::App::[Windows::ApplicationModel::Core::IFrameworkView]::__abi_Windows_ApplicationModel_Core_IFrameworkView____abi_Run()
twinapi.appcore.dll!Windows::ApplicationModel::Core::CoreApplicationView::Run()
twinapi.appcore.dll!<lambda>(void)()
SHCore.dll!_WrapperThreadProc()
kernel32.dll!BaseThreadInitThunk()
ntdll.dll!RtlUserThreadStart()```

Hey,

I’m really sorry to hear about this bug, but thank you for reporting it. I’d thought we’d fixed the race-conditions and deadlocks within the CoreTextEditControlContext implementation, but apparently we missed something.

Do you happen to know if this also repros in 2020+ releases?

I can start investigating the problem, but please file a Bug Report so we can properly track it.

Bug Report created

https://fogbugz.unity3d.com/default.asp?1321299_6m1l78htjqsj6mfc

Update on this issue:

I verified this bug was been fixed but not yet backported to 2019 LTS. It was discovered and fixed internally, and so didn’t have an actual ticket assigned to it.

I have pending 2019 backports for TouchScreenKeyboard and InputField fixes, which does include this fix. Given the severity of the problem for you, I’ll expedite the backports as best I can.

Thank you again for posting this problem, as I didn’t realize how serious the bug was; it only rarely occurs for us.