-
Notifications
You must be signed in to change notification settings - Fork 874
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
Attempted clipboard issue workaround on Windows #8277
base: master
Are you sure you want to change the base?
Conversation
…board.setContents from the Event Dispatch Thread.
Hi. This is not the issue and won't really help. You can call |
@xxDark Just to confirm; did the change in that OpenJDK PR fix the original problem in NetBeans, rather than just avoiding the assertion failures? Did you figure out how calling handleContentsChanged from the wrong thread could end up causing IsGettingOwnership to return true when it shouldn't? Our challenge is that we can't easily change the JDK, but we can easily make changes to NetBeans, if a workaround can be found there. |
Yes, I've verified that this fixes the issue. |
I've published the agent to https://github.com/xxDark/clipboard-agent. Someone from NetBeans team can adapt it as I've not figured out how to set the project up properly in IntelliJ, unfortunately. |
@xxDark Whoa, I didn't know you could do that! Thanks for posting and documenting the agent code. I think we could adapt that, if nobody discovers a simpler workaround. |
@eirikbakke well, we did just decide against adding an agent from #3386 as part of #7928 That also has clipboard implications to address in NB26. |
@neilcsmith-net Yeah, it's a bit of a heavy-handed approach. I'd prefer if we could find a simpler workaround. I still think it would be worth testing this PR, in case there are bugs that make setContents not fully thread-safe. |
I can probably make a workaround that does not need a java agent specifically for NetBeans, but that will require working with JDK internals regardless. If that is OK to do so, then I can probably make a PR |
if it is indeed a JDK bug, getting it in should have priority IMO. Workarounds are just distractions which would have to be removed again anyway most likely. This bug exists since pre-apache times its not something what has to be rushed. Some JDK bugs are also backported, this is something what we can't do in NB since the major versions go only forward with no hotfixes - JDK update would cover that too. JDK PRs won't even reach the mailing list before the paperwork is done. Would be good to get in touch with someone from the JDK client team but I don't know anyone (anymore) unfortunately. And just-to-be-sure it would be good to check that this is indeed fixing the issues of those who are affected. If it would be linux I would have hosted a JDK dev build by now but I don't want to setup a win image in vbox right now. |
I think that it would be great if some users could test the agent (edit: or, I could implement some hack in NetBeans to address this issue without the agent, if it is OK to reach into JDK internals, effectively achieving the same fix) to see if it fixes the issue. Would be awkward if it ends up not fixing the bug (although assert failures in the OpenJDK already show that something is wrong..). |
yep. I am a bit busy right now, but any other PMC could take a look through the agent code and if its ok create a dev build of NB (via PR) for testing purposes which injects it on startup, then post a mail to dev/users to get feedback etc. Thanks for putting so much effort into this btw @xxDark |
(i mean. It doesn't even need a dev build. the instructions in the agent readme should be enough.) |
BOOL __stdcall OpenClipboard(HWND hWndNewOwner)
{
DWORD emptyClipboard;
DWORD result = NtUserOpenClipboard(hWndNewOwner, &emptyClipboard);
if ( emptyClipboard )
ClientEmptyClipboard();
return result;
} Call to void ClientEmptyClipboard(void)
{
struct _HANDLENODE *v0; // rbx
struct _HANDLENODE *v1; // rdi
RtlEnterCriticalSection(&gcsClipboard);
v0 = (struct _HANDLENODE *)gphn;
if ( gphn )
{
do
{
v1 = *(struct _HANDLENODE **)v0;
if ( *((_QWORD *)v0 + 3) )
DeleteClientClipboardHandle(v0);
RtlFreeHeap(pUserHeap, 0, v0);
v0 = v1;
}
while ( v1 );
}
gphn = 0LL;
if ( pfnWowEmptyClipBoard )
pfnWowEmptyClipBoard(); // Supposed to send WM_DESTROYCLIPBOARD here, but because OpenClipboard did not succeed, the message is silently discarded (?)
RtlLeaveCriticalSection(&gcsClipboard);
}
|
@xxDark curious on your thoughts on the patch at JetBrains/JetBrainsRuntime@6b2c6ff Mind you we know JBR doesn't fix the issue for some reporters here, and I also noticed people are reporting the issue isn't fixed there either, and are even referring to the bug report and replicator in NetBeans. |
Yep, sounds exactly like the issue in JDK we pinpointed. |
I think it doesn't fix the issue because to me it seems like a hacky attempt to fix the main issue with the race condition that was found. The toolkit is still calling OpenClipboard without proper synchronization on Java side. |
After more digging, to answer your question @eirikbakke: I can't say for sure the cause of this.
One thing for certain is that there is a flaw at how JDK handles clipboard access IMO. Logic like this for example is equivalent to this: try {
lock.lock();
....
} finally {
lock.unlock();
} What if |
I can confirm that clipboard-agent is working fine! Nice job! |
@xxDark Thanks for the further investigation! That's a very useful writeup for the future. @johntor Thanks for testing! Did you observe copy/paste bugs in the past, which were eliminated by the agent? EDIT: And in particular, I noticed in another thread that you have also been experimenting with changes to the SecurityManager settings. It would be useful to know how sure you are that the bug is fixed by the xxDark's "agent" workaround, as opposed to other changes you may have experimented with. E.g. disable the agent, run NetBeans until you see the cut/paste bugs, then enable the agent without making any other configuration changes, and see how long you can go without seeing the cut/paste bugs. |
Try to work around clipboard issues on Windows by always calling Clipboard.setContents from the Event Dispatch Thread.
This attempted workaround was motivated by @xxDark's investigation here.
The problem mentioned was that IsGettingOwnership would be returning true when awt_toolkit.cpp in the JDK tries to handle the WM_DESTROYCLIPBOARD event from the Win32, leading to the event being left unhandled and the cached clipboard content in Clipboard.contents remaining stale.
Grepping through the OpenJDK codebase, the IsGettingOwnership flag seems only to be modified when Java_sun_awt_windows_WClipboard_openClipboard is called with a non-null argument for newOwner. This, in turn, happens only when Clipboard.setContents is called.
Since race condition is related to a flag touched only by Clipboard.setContents, I am inclined to test this workaround where we call setContents only from the Event Dispatch Thread.
Note that IsGettingOwnership is called from the Toolkit thread, not the Event Dispatch Thread; from @xxDark's explanation I understand that these are different. But there's a high chance that the Toolkit thread and the EDT are "better" synchronized than the Toolkit thread and a random RequestProcessor thread.
Unfortunately I have never been able to reproduce the clipboard bug reliably on my own machine, and I spent my time mostly on MacOS these days. So I'm leaving this PR here for others to try if they have the chance.