diff options
author | Alexandr Miloslavskiy | 2020-10-13 07:26:20 +0000 |
---|---|---|
committer | Andrey Loskutov | 2020-11-23 09:27:10 +0000 |
commit | 631d51aa69013b49cc537c25eef14e741cd30973 (patch) | |
tree | 1d77e011aaec2a0cd968af5c3350225d157608e1 | |
parent | aff50918b0e8c5cc3a8266e59d0b880f57296704 (diff) | |
download | eclipse.platform.swt-631d51aa69013b49cc537c25eef14e741cd30973.tar.gz eclipse.platform.swt-631d51aa69013b49cc537c25eef14e741cd30973.tar.xz eclipse.platform.swt-631d51aa69013b49cc537c25eef14e741cd30973.zip |
Bug 567826 - [GTK] JVM crash on Display.dispose() due to Clipboard
If 'SWT.Dispose' handler is a bit slow, user might be able to switch to
other application and Ctrl+C there. When this happens, Linux calls
'ClipboardProxy.clearFunc()' with the following stack:
Native: clipboard_unset() at gtk/gtkclipboard.c:782
Native: selection_clear_event_cb() at gtk/gtkclipboard.c:424
Native: <emit signal for 'GDK_SELECTION_CLEAR'>
Native: gtk_widget_event_internal() at gtk/gtkwidget.c:7808
Native: gtk_main_do_event() at gtk/gtkmain.c:1860
Java: org.eclipse.swt.internal.gtk.GTK._gtk_main_do_event()
Java: org.eclipse.swt.widgets.Display.eventProc()
Java: org.eclipse.swt.internal.gtk.OS._g_main_context_iteration()
Java: org.eclipse.swt.widgets.Display.readAndDispatch()
Java: org.eclipse.swt.widgets.Display.release()
If 'Callback' for 'clearFunc' is already disposed, JVM crashes.
The solution is to dispose callback after 'Display.readAndDispatch()' in
'Display.release()'.
This patch has a curious side effect: if 'SWT.Dispose' handler is slow,
Shell is now visible (and eventually shows "not responding") for its
duration. I understand that this is because 'gtk_clipboard_store()'
also does some unexpected event processing. I consider this side effect
as not a regression because the same behavior is seen when clipboard is
not owned by SWT by the time of 'Display.dispose()'.
Change-Id: I2cc11600f06030243e55d70f24b881dcb9b67503
Signed-off-by: Alexandr Miloslavskiy <alexandr.miloslavskiy@syntevo.com>
3 files changed, 86 insertions, 3 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/ClipboardProxy.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/ClipboardProxy.java index 5eee958934..54cde28b5e 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/ClipboardProxy.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/ClipboardProxy.java @@ -14,7 +14,6 @@ package org.eclipse.swt.dnd; -import org.eclipse.swt.*; import org.eclipse.swt.internal.*; import org.eclipse.swt.internal.gtk.*; import org.eclipse.swt.widgets.*; @@ -43,7 +42,7 @@ static ClipboardProxy _getInstance(final Display display) { if (proxy != null) return proxy; proxy = new ClipboardProxy(display); display.setData(ID, proxy); - display.addListener(SWT.Dispose, event -> { + display.disposeExec(() -> { ClipboardProxy clipbordProxy = (ClipboardProxy)display.getData(ID); if (clipbordProxy == null) return; display.setData(ID, null); diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/SWT.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/SWT.java index d13183afd2..5b87b09228 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/SWT.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/SWT.java @@ -258,11 +258,17 @@ public class SWT { public static final int Resize = 11; /** - * The dispose event type (value is 12). + * The dispose event type (value is 12).<br> + * <br> + * Note: {@link Display} still runs {@link Display#readAndDispatch} + * after sending this event. If you want to dispose any resources, + * this might cause problems. Use {@link Display#disposeExec} + * instead. * * @see org.eclipse.swt.widgets.Widget#addListener * @see org.eclipse.swt.widgets.Display#addListener * @see org.eclipse.swt.widgets.Display#addFilter + * @see org.eclipse.swt.widgets.Display#disposeExec * @see org.eclipse.swt.widgets.Event * * @see org.eclipse.swt.widgets.Widget#addDisposeListener diff --git a/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug567826_CrashClipboardExit.java b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug567826_CrashClipboardExit.java new file mode 100644 index 0000000000..6e70335243 --- /dev/null +++ b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug567826_CrashClipboardExit.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2020 Syntevo and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Syntevo - initial API and implementation + *******************************************************************************/ + +package org.eclipse.swt.tests.gtk.snippets; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.dnd.Clipboard; +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.widgets.*; + +public class Bug567826_CrashClipboardExit { + public static void main (String [] args) { + Display display = new Display (); + + FillLayout layout = new FillLayout(); + layout.marginHeight = 10; + layout.marginWidth = 10; + + Shell shell = new Shell(display); + shell.setLayout(layout); + + Label hint = new Label(shell, SWT.NONE); + hint.setText( + "1) Close this Shell\n" + + "2) There will be a 10 sec Thread.sleep()\n" + + "3) During the sleep, switch to other app and copy some text to clipboard\n" + + "4) JVM will crash.\n" + ); + + Clipboard clipboard = new Clipboard(display); + Object[] data = new Object[]{"Test clipboard contents"}; + Transfer[] types = new Transfer[]{TextTransfer.getInstance()}; + clipboard.setContents(data, types, DND.CLIPBOARD); + + final String clipboardProxyID = "CLIPBOARD PROXY OBJECT"; + if (null == display.getData(clipboardProxyID)) + System.out.println("Unexpected: ClipboardProxy is not present"); + + display.addListener(SWT.Dispose, event -> { + System.out.println("SWT.Dispose for Display: waiting"); + if (null != display.getData(clipboardProxyID)) + System.out.println("ClipboardProxy is not disposed in SWT.Dispose. Shouldn't happen without the patch."); + + // Give time to switch to other window + try { + Thread.sleep(10000); + } catch (InterruptedException ex) { + ex.printStackTrace(); + } + + System.out.println("SWT.Dispose for Display: continuing"); + }); + + shell.pack(); + shell.open(); + + while (!shell.isDisposed()) { + if (!display.readAndDispatch ()) + display.sleep (); + } + + display.dispose (); + } +} |