Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexandr Miloslavskiy2020-10-13 07:26:20 +0000
committerAndrey Loskutov2020-11-23 09:27:10 +0000
commit631d51aa69013b49cc537c25eef14e741cd30973 (patch)
tree1d77e011aaec2a0cd968af5c3350225d157608e1
parentaff50918b0e8c5cc3a8266e59d0b880f57296704 (diff)
downloadeclipse.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>
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/ClipboardProxy.java3
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/SWT.java8
-rw-r--r--tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug567826_CrashClipboardExit.java78
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 ();
+ }
+}

Back to the top