Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clipboard.GetContent() often crashes with a stowed exception (c000027b) #6754

Open
1 of 2 tasks
wbokkers opened this issue Feb 21, 2022 · 25 comments
Open
1 of 2 tasks
Labels
bug Something isn't working Crash whenever user reports a crash or app freeze product-winui3 WinUI 3 issues team-Reach Issue for the Reach team

Comments

@wbokkers
Copy link

wbokkers commented Feb 21, 2022

Describe the bug

Calling Clipboard.GetContent() often result in a crash that cannot be handled.
The only message I get while debugging, is a c000027b exception (stowed exception), but there's no managed exception that I can catch.

My use case it to override the default paste behavior of a TextBox. When the user pastes a binary (e.g. an image), I need to handle this as well. This is needed for a chat-like experience to send either text or binary attachments.

Steps to reproduce the bug

Coding steps:

  1. Create a WinUI/WindowsAppSDK 1.0/C#/XAML app
  2. Add a TextBox
  3. Implement the Paste-event of the TextBox
  4. In the Paste-handler, set e.Handle = true;
  5. In the Paste-handler call Clopboard.GetContent();

Usage steps:

  1. Switch away from the app
  2. Switch to the app so that it becomes active
  3. Put some text or binary in the textbox
  4. Repeat step 1 to 3 until a crash occurs (it can take a while).

Expected behavior

I can understand that the clipboard needs to throw an exception if the current application is not active.
But this should be a managed exception that I can handle in code.

Expected behavior:

  • Never ever crash the app with a stowed exception.
  • Throw an managed exception when the application is not active or for other exceptional cases.

Screenshots

No response

NuGet package version

WinUI 3 - Windows App SDK 1.0

Windows app type

  • UWP
  • Win32

Device form factor

Desktop

Windows version

May 2021 Update (19043)

Additional context

No response

@ghost ghost added the needs-triage Issue needs to be triaged by the area owners label Feb 21, 2022
@castorix
Copy link

I cannot reproduce that
Tested on the default click Button, Windows 10 21H1, VS 2022

@wbokkers
Copy link
Author

@castorix I have a slightly different use case. I changed the steps to reproduce. Can you reproduce it now?

@castorix
Copy link

@castorix I have a slightly different use case. I changed the steps to reproduce. Can you reproduce it now?

I still could not reproduce it
I adapted code from TextBox.Paste Event

@wbokkers
Copy link
Author

wbokkers commented Feb 21, 2022

@castorix Thanks for trying. That code is indeed where the crash occurs. It does not occur frequently and some users see it far more often than others. I have the feeling it is some timing issue / race condition and therefor can depend on the machine specs.
I can reproduce it in the debugger when setting the breakpoint just before de Clipboard.GetContent() and stepping over this than crashes the app. But also infrequently.

@wbokkers
Copy link
Author

@castorix If this issue can be reproduced or not: bottom line of these types of issues is that some low level exceptions crash the complete app without any clue on why this is happening.

@castorix
Copy link

As Workaround, maybe you can test if Clipboard APIs crash too :
Clipboard APIs Test in Paste event

@wbokkers
Copy link
Author

wbokkers commented Feb 21, 2022

That's what I do now. I don't see a crash in the low level win32 API's, so it must be located in the Clipboard implementation.
I use the win32 API with P/Invoke for text. For binaries I still rely on Clipboard, until I can dream up a good implementation of all the kinds of binaries I want to handle using win32 APIs only.

@StephenLPeters StephenLPeters added product-winui3 WinUI 3 issues team-Reach Issue for the Reach team labels Mar 5, 2022
@asklar
Copy link
Member

asklar commented Mar 6, 2022

Some reasons Clipboard.GetContent might throw:

  • it wasn't called from the UI thread
  • another app had locked the clipboard
  • the app didn't have focus (wasn't in the foreground) when trying to read the clipboard

@wbokkers
Copy link
Author

wbokkers commented Mar 7, 2022

@asklar If it just throws an exception I can handle, I would not complain. The clipboard crashes the app without getting the opportunity to catch the exception.
Of course I checked all your bullet points.

  • I make sure the clipboard is always called from the UI thread.
  • Maybe this is the case, but I don't think so, because I can access it with win32 api's without issues.
  • The app has focus (the user does select a textbox and pastes in the text box)

But again, this is not the issue I'm complaining about. Please read carefully. The issue is that I can't catch the exception and the app crashes right away

@asklar
Copy link
Member

asklar commented Mar 7, 2022

@wbokkers I just tried to reproduce it myself, and I don't see the crash either.
I suggest you take a look at the instructions for investigating stowed exceptions here: Stowed exception crashes.

@wbokkers
Copy link
Author

wbokkers commented Mar 7, 2022

I don't see the issue myself if I try to reproduce. The crash occurs seldom.
Why is it so difficult to catch these kind of exceptions and throw them as managed exceptions instead?
I don't want to 'investigate a stowed exception'. That is really not the point. There should be no exceptions I can't handle myself. This is the issue.

Maybe I should rephrase it:
What am I supposed to do in my code to see if another app locked the clipboard? How is the Clipboard class designed so that I can handle this situation?
I think the answer to this question is telling.

@wbokkers
Copy link
Author

wbokkers commented Mar 29, 2022

It just crashed again. I managed to save a crash dump. Where can I send the crash dump?

image

The following message appears in the output window. I don't know if it is related to this issue:

onecore\Base\AppModel\Runtime\Src\PackagePath.hpp(144)\kernelbase.dll!00007FFC618F67CD: (caller: 00007FFC618F5FCE) ReturnHr(8) tid(8074) 80073D5B The package does not have a mutable directory.

@wbokkers
Copy link
Author

wbokkers commented Mar 29, 2022

Opened the dump file with WinDbg. I don't know what to do exactly, but I got these messages:

This dump file has an exception of interest stored in it.
The stored exception information can be accessed via .ecxr.
(32c4.8074): Unknown exception - code c000027b (first/second chance not available)
For analysis of this file, run !analyze -v
ntdll!NtWaitForSingleObject+0x14:
00007ffc`643037d4 c3              ret
0:000> .ecxr
rax=0000009a9b5788e0 rbx=0000009a9b578ec0 rcx=0000009a9b5788e0
rdx=0000009a9b578d90 rsi=000002168a6cdb01 rdi=0000009a9b5788e0
rip=00007ffc61a22492 rsp=0000009a9b578800 rbp=0000000000000001
 r8=0000000000000000  r9=0000009a9b578d40 r10=0000000000000000
r11=0000009a9b578ec0 r12=0000000000000485 r13=0000000080070057
r14=0000000000000002 r15=0000000000000002
iopl=0         nv up ei pl nz na po nc
cs=0033  ss=002b  ds=0000  es=0000  fs=0000  gs=0000             efl=00000204
KERNELBASE!RaiseFailFastException+0x152:
00007ffc`61a22492 0f1f440000      nop     dword ptr [rax+rax]

@wbokkers
Copy link
Author

@asklar Can I send the dump-file to you or someone else at Microsoft?

@wbokkers
Copy link
Author

@asklar Here is the WinDbg analysis:
ClipboardGetContent-WinDbg-Output.txt

@codendone
Copy link
Contributor

@wbokkers Thanks for sharing that debugger output! What the stack shows is unsupported reentrancy, where the Clipboard.GetContent() call went into CoCreateInstance() to create an out-of-proc COM object, which created a COM message pump (combase!ModalLoop) which pumped a message which ended up back in XAML (Microsoft_ui_xaml!CXcpDispatcher::OnReentrancyProtectedWindowMessage). The complete stack isn't shown, but since the crash was in OnReentrancyProtectedWindowMessage that means that farther down the stack XAML was delivering an event (presumably the textbox paste event). XAML currently doesn't support reentrancy at certain times, including firing some events and when rendering (including layout passes at the start of the render process).

UWP uses the ASTA threading model which helps prevent reentrancy. Without that, the general recommendation for potential reentrancy issues is to delay processing until after XAML is off the stack, such as via DispatcherQueue.TryEnqueue().

There might be a chance for this specific case that calling Clipboard.GetContent() once while XAML is not on the stack might allow it to work while XAML is on the stack, if the underlying COM object gets cached after it is first created. I don't know if it does, though, or if its lifetime is guaranteed after that point.

@wbokkers
Copy link
Author

@codendone Thank you for your response.

Currently when I want to run something on the UI-thread I do the following:
if (dispatcherQueue.HasThreadAccess) action(); else dispatcherQueue.TryEnqueue(() => action());
Is this sufficient to prevent the reentrancy issue? I suspect that I should not check for thread access and always dispatch the action. Is this true? If this is true, is it always better to always enqueue actions on the dispatcher queue and never check for thread access?

Will these type of issues be eventually solved in the XAML/WinRT layers? I think it is not ok to get in all kind of COM/threading-trouble by just calling higher level APIs.

@codendone
Copy link
Contributor

The code you mentioned is great if you need to ensure some code runs on the UI thread. Your suspicion is correct that for this Clipboard issue it is additionally necessary to ensure the UI thread stack doesn't have XAML in a "no reentrancy allowed" state, and therefore the safest bet for that is to always dispatcherQueue.TryEnqueue(() => action()) even if already on the UI thread.

We do want to improve XAML and other parts of the platform to safely handle reentrancy. This is a sizeable challenge since so much code was written assuming ASTA and some parts need to be redesigned for this situation. We have some known work booked work for this over the next few months, some less known investigation booked, and there are likely some unknown unknowns. It isn't clear yet how long it will take. There may be a release during this process which includes a change to help find problematic reentrancy so at least such problems can be consistently found and addressed.

@wbokkers
Copy link
Author

Thank you @codendone !
I did not yet run into the crash when following your advice. So hopefully this solves our issue for the time being.

Nice to know that this is on your radar and that XAML will be improved to better fit WinUI3.

Do you think it is wise to always run TryEnqueue and never check for thread access first every time I want to run something on the UI to prevent these type of issues?

@codendone
Copy link
Contributor

If the code might use a COM object, then always doing a TryEnqueue, if possible, would be a good idea. If it is doing something simpler, such as setting some properties on elements, then there should be no need to TryEnqueue if already on the UI thread so having the thread access check in that case would be good for efficiency.

@bpulliam
Copy link
Contributor

Is this issue still active. I'm not sure about next steps. Thanks!

@bpulliam bpulliam added Crash whenever user reports a crash or app freeze and removed needs-triage Issue needs to be triaged by the area owners labels Oct 18, 2022
@wbokkers
Copy link
Author

@bpulliam If it is still an issue, it should be mentioned in the documentation that you can only access the clipboard in a TryEnqueue. But it would be better if TryEnqueue is not needed for clipboard access.

@wbokkers
Copy link
Author

@bpulliam What should be done is mentioned by @codendone : "We do want to improve XAML and other parts of the platform to safely handle reentrancy. "
I really hope this is still the plan. If this crash happens due to reentrancy not being safe, it can happen all over the place.

@github-actions
Copy link

This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 5 days.

@tipa
Copy link
Contributor

tipa commented Jul 30, 2023

Are there still plans to improve/fix this?
It shouldn't be necessary to use TryEnqueue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working Crash whenever user reports a crash or app freeze product-winui3 WinUI 3 issues team-Reach Issue for the Reach team
Projects
None yet
Development

No branches or pull requests

8 participants