wpf icon indicating copy to clipboard operation
wpf copied to clipboard

RichTextBox insert text application will crash

Open Luoyingliang opened this issue 5 years ago • 20 comments

  • .NET Core Version: netcoreapp 3.1
  • Windows version: Windows 10 CMGE
  • Does the bug reproduce also in WPF for .NET Framework 4.8?: Yes
  • Is this bug related specifically to tooling in Visual Studio (e.g. XAML Designer, Code editing, etc...)? No.
  • Security issues and bugs should be reported privately, learn more via our responsible disclosure guidelines.

Problem description: the problem occur when we set the caret on the BlockUIContainer and typing any character,that will raise FatalExecutionEngineError in framework 4.7.2 or raise ExecutionEngineException in netcore 3.1.

How to reproduce?

  1. create an wpf project,and add this xaml code to mainwindow.xaml
<RichTextBox>
            <FlowDocument>
                <BlockUIContainer>
                    <Image Source="D:\sample.jpg"/>
                </BlockUIContainer>
            </FlowDocument>
        </RichTextBox>
  1. use an image file to instead D:\sample.jpg
  2. run app
    4.click image and press Arrow-Right
    5.type any character

Luoyingliang avatar Oct 12 '20 02:10 Luoyingliang

we test in another device,this problem reproduce again

Luoyingliang avatar Oct 14 '20 01:10 Luoyingliang

@Luoyingliang This doesn't repro in latest .NET releases. Could you please confirm and check once?

singhashish-wpf avatar Nov 23 '22 04:11 singhashish-wpf

reproduce repo is in here: https://github.com/Luoyingliang/RichTextBoxCrash

Luoyingliang avatar Dec 01 '22 03:12 Luoyingliang

I cannot reproduce, neither in .NET FW 4.8, 4.7.2 nor in .NET 6.0.

miloush avatar Dec 01 '22 16:12 miloush

ither in .NET FW 4.8, 4.7.2 nor in .NET 6.0.

emmm,maybe I can register an youtube account and upload a video ? In china this issue reproduce by many people

Luoyingliang avatar Jan 11 '23 14:01 Luoyingliang

I think you can upload videos to GitHub. Try, maybe we will see something we missed in the repro steps.

miloush avatar Jan 11 '23 16:01 miloush

the video in here https://user-images.githubusercontent.com/29297262/211973242-63f26cbf-4926-43b9-b001-0511b09d5f4e.mp4

Luoyingliang avatar Jan 12 '23 04:01 Luoyingliang

Ohhh okay so the missing bit in the repro is that you are using an IME. "Typing any character" should be "start composition" - it does not repro with simple input methods such as US keyboard. I can reproduce now in both FW and Core. This is the failing assert:

https://github.com/dotnet/wpf/blob/c92f5ed2e8b0ae68cf67757c4f2634599a32d1d3/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/TextStore.cs#L3349-L3357

miloush avatar Jan 12 '23 12:01 miloush

Ohhh okay so the missing bit in the repro is that you are using an IME. "Typing any character" should be "start composition" - it does not repro with simple input methods such as US keyboard. I can reproduce now in both FW and Core. This is the failing assert:

https://github.com/dotnet/wpf/blob/c92f5ed2e8b0ae68cf67757c4f2634599a32d1d3/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/TextStore.cs#L3349-L3357

thanks a lots

Luoyingliang avatar Jan 12 '23 12:01 Luoyingliang

Ohhh okay so the missing bit in the repro is that you are using an IME. "Typing any character" should be "start composition" - it does not repro with simple input methods such as US keyboard. I can reproduce now in both FW and Core. This is the failing assert:

https://github.com/dotnet/wpf/blob/c92f5ed2e8b0ae68cf67757c4f2634599a32d1d3/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/TextStore.cs#L3349-L3357

Wait a minute, this issues also crash without ime composition

Luoyingliang avatar Jan 12 '23 12:01 Luoyingliang

Ohhh okay so the missing bit in the repro is that you are using an IME. "Typing any character" should be "start composition" - it does not repro with simple input methods such as US keyboard. I can reproduce now in both FW and Core. This is the failing assert: https://github.com/dotnet/wpf/blob/c92f5ed2e8b0ae68cf67757c4f2634599a32d1d3/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/TextStore.cs#L3349-L3357

Wait a minute, this issues also crash without ime composition

right, using ime will crash

Luoyingliang avatar Jan 12 '23 12:01 Luoyingliang

TextContainer/TextStore have inconsistent char counts!

so the problem is IMECharCount counting miss?

Luoyingliang avatar Jan 12 '23 12:01 Luoyingliang

I think it has to do with the text pointer being inside the BlockUIContainer. Typing then has to create a paragraph, which adds a character to the IMECharCount but _netCharCount is not updated. Checking how it works without IME.

miloush avatar Jan 12 '23 12:01 miloush

I think it has to do with the text pointer being inside the BlockUIContainer. Typing then has to create a paragraph, which adds a character to the IMECharCount but _netCharCount is not updated. Checking how it works without IME.

got it! thanks a lot

Luoyingliang avatar Jan 12 '23 12:01 Luoyingliang

Looks like I was correct.

In the non-IME case, all changes are initiated from WPF, implicit paragraph is created and text put into it. Both changes cause TextStore.OnTextContainerChange to update and they update the _netCharCount.

In the IME case, changes are coming from TSF, and the composition comes in via TextStore.SetText, after the TSF issues a lock on the store. According to SetText documentation, ITextStoreACPSink::OnTextChange should not be called during the call and that is indeed the case, if there is a lock, WPF does not inform the sink of changes.

As a result, the implicit paragraph creation does not cause TextStore.OnTextContainerChange and therefore _netCharCount is not updated. We could fire the event, update the internal count & not inform the sink, however, then the inserted text will be counted twice - once in the OnTextContainerChange and once in the SetText method. The problem is that the SetText must return which range was affected, but without the events it doesn't know whether an extra paragraph had to be inserted or not.

I also suspect there is an undiscovered bug when filtering in TextBox takes place during IME composition, since the reported changed range uses the original text, not the filtered text.

One option would be to remember somewhere that a paragraph has been added and bump _netCharCount accordingly. Another option is to make the assumption that any changes in length during TextEditor.SetText are due to the text being set and follow the insertion point. Then the SetText could remember the length before and after change and add anything extra to the range changed.

miloush avatar Jan 12 '23 15:01 miloush

the SetText could remember the length before and after change and add anything extra to the range changed.

This seems to fix the crash, but the composition gets confused.

miloush avatar Jan 12 '23 15:01 miloush

Basically I think it is illegal to add a paragraph during SetText since TSF has a lock on the store. Citing the documentation:

Applications must never modify the document or send change notifications using the ITextStoreACPSink::OnTextChange method from within the ITextStoreACP::RequestLock method.

For the first option, if the _netCharCount is updated with the correct value in SetText, the crash is fixed (by definition) and the IME works uninterrupted, but I believe we should technically inform the sink that a paragraph has been added once the lock is lifted. This is a bit tricky because we need to track where the paragraph insertion ends up being after the composition.

miloush avatar Jan 12 '23 16:01 miloush

It seems that the ExecutionEngineException or FatalExecutionEngineError can be also observed in case of Emoji panel, which is available in Windows 11:

  • Using Visual Studio 2022, create a new project: C#, “WPF Application”, .NET 9.0,
  • Open the MainWindow.xaml and insert the RichTextBox:
<RichTextBox>
    <FlowDocument>
        <Paragraph>
            <Run>a</Run><Italic>b</Italic><Bold>c</Bold>
        </Paragraph>
        <Paragraph>
            <Run>d</Run>
        </Paragraph>
    </FlowDocument>
</RichTextBox>
  • Start the program in Debug mode,
  • Select the whole text in RichTextBox using <Ctrl + A>,
  • Press <Win + ;> to display the Emoji panel, then click an emoji like “💕”,
  • The exception will be raised.

The problem does not seem to occur in Windows 10, or if the RichTextBox contains fewer or different elements, or if the emoji is pasted from Clipboard.

I hope that the problem can be reproduced on other computers.

Viorel avatar Sep 10 '25 18:09 Viorel

@Viorel Can I know your stacktrace? Do you enable the Win11 text cursor indicator?

Image

lindexi avatar Sep 17 '25 07:09 lindexi

The Text Cursor Indicator was disabled. The error occurs regardless of this indicator. In both cases, the Stack Trace is:

 	[Managed to Native Transition]	
>	System.Private.CoreLib.dll!System.Environment.FailFast(System.Runtime.CompilerServices.StackCrawlMarkHandle mark, string message, System.Runtime.CompilerServices.ObjectHandleOnStack exception, string errorMessage) Line 369	C#
 	System.Private.CoreLib.dll!System.Environment.FailFast(ref System.Threading.StackCrawlMark mark, string message, System.Exception exception, string errorMessage) Line 83	C#
 	System.Private.CoreLib.dll!System.Environment.FailFast(string message) Line 44	C#
 	WindowsBase.dll!MS.Internal.Invariant.FailFast(string message, string detailMessage)	Unknown
 	PresentationFramework.dll!System.Windows.Documents.TextStore.GrantLock()	Unknown
 	PresentationFramework.dll!System.Windows.Documents.TextStore.GrantLockWorker(MS.Win32.UnsafeNativeMethods.LockFlags flags)	Unknown
 	PresentationFramework.dll!System.Windows.Documents.TextStore.RequestLock(MS.Win32.UnsafeNativeMethods.LockFlags flags, out int hrSession)	Unknown
 	[Native to Managed Transition]	
 	[Managed to Native Transition]	
 	PresentationFramework.dll!System.Windows.Documents.TextStore.OnLayoutUpdated()	Unknown
 	PresentationFramework.dll!System.Windows.Documents.TextEditor.OnTextViewUpdatedWorker(object o)	Unknown
 	WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate callback, object args, int numArgs)	Unknown
 	WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.TryCatchWhen(object source, System.Delegate callback, object args, int numArgs, System.Delegate catchHandler)	Unknown
 	WindowsBase.dll!System.Windows.Threading.DispatcherOperation.InvokeImpl()	Unknown
 	WindowsBase.dll!MS.Internal.CulturePreservingExecutionContext.CallbackWrapper(object obj)	Unknown
 	System.Private.CoreLib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) Line 179	C#
 	WindowsBase.dll!MS.Internal.CulturePreservingExecutionContext.Run(MS.Internal.CulturePreservingExecutionContext executionContext, System.Threading.ContextCallback callback, object state)	Unknown
 	WindowsBase.dll!System.Windows.Threading.DispatcherOperation.Invoke()	Unknown
 	WindowsBase.dll!System.Windows.Threading.Dispatcher.ProcessQueue()	Unknown
 	WindowsBase.dll!System.Windows.Threading.Dispatcher.WndProcHook(nint hwnd, int msg, nint wParam, nint lParam, ref bool handled)	Unknown
 	WindowsBase.dll!MS.Win32.HwndWrapper.WndProc(nint hwnd, int msg, nint wParam, nint lParam, ref bool handled)	Unknown
 	WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate callback, object args, int numArgs)	Unknown
 	WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.TryCatchWhen(object source, System.Delegate callback, object args, int numArgs, System.Delegate catchHandler)	Unknown
 	WindowsBase.dll!System.Windows.Threading.Dispatcher.LegacyInvokeImpl(System.Windows.Threading.DispatcherPriority priority, System.TimeSpan timeout, System.Delegate method, object args, int numArgs)	Unknown
 	WindowsBase.dll!MS.Win32.HwndSubclass.SubclassWndProc(nint hwnd, int msg, nint wParam, nint lParam)	Unknown
 	[Native to Managed Transition]	
 	[Managed to Native Transition]	
 	WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame frame)	Unknown
 	PresentationFramework.dll!System.Windows.Application.RunDispatcher(object ignore)	Unknown
 	PresentationFramework.dll!System.Windows.Application.RunInternal(System.Windows.Window window)	Unknown
 	WpfApp27.dll!WpfApp27.App.Main()	Unknown

It seems that the exception is raised in TextStore.GrantLock().

Viorel avatar Sep 17 '25 07:09 Viorel