eclipse-platform / eclipse.platform.swt

Eclipse SWT
https://www.eclipse.org/swt/
Eclipse Public License 2.0
101 stars 123 forks source link

[Mac] SIGSEGV Crash to desktop when pressing Cmd-Z in Text Control #1273

Open Phillipus opened 3 weeks ago

Phillipus commented 3 weeks ago

macOS 13.6.7 and 14.5 Silicon SWT version 3.126.0.v20240528-0813 Java Temurin 17.0.9+9

Run the Snippet below:

  1. Type a few characters in the text control
  2. Press the button to dispose of the text control and create a new one
  3. Press Cmd-Z (Undo) for a crash
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

public class MacTextControlCrash {

    static Text textControl;

    public static void main(String[] args) {
        Display display = new Display();
        Shell shell = new Shell(display);
        shell.setText("Mac Text Control Bug");
        shell.setLayout(new GridLayout());

        Button b  = new Button(shell, SWT.PUSH);
        b.setText("New Text Control");
        b.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent evt) {
                // Dispose of text control and create a new one
                textControl.dispose();
                textControl = createTextControl(shell, "Now press Cmd-Z");
                shell.layout();
            }
        });

        textControl = createTextControl(shell, "Type something here and then click the button above.");

        shell.setSize(300, 250);
        shell.open();

        while(!shell.isDisposed()) {
            if(!display.readAndDispatch()) {
                display.sleep();
            }
        }

        display.dispose();
    }

    static Text createTextControl(Composite parent, String text) {
        Text textControl = new Text(parent, SWT.MULTI | SWT.WRAP);
        GridDataFactory.create(GridData.FILL_BOTH).applyTo(textControl);
        textControl.setText(text);
        textControl.setFocus();
        return textControl;
    }
}

This is happening with a SWT.MULTI text control, not SWT.SINGLE.

I think this has been like this for some time so I can't say if this has always been a bug. I have no idea what causes this or how to fix it. @lshanmug do you have an idea?

Phillipus commented 3 weeks ago

Crash log attached. hs_err_pid4382.log

Phillipus commented 3 weeks ago

The area of interest is, I think, here:

https://github.com/eclipse-platform/eclipse.platform.swt/blob/ece679cd0c03d2bbb15ac1d07c6e81bddce02ab9/bundles/org.eclipse.swt/Eclipse%20SWT/cocoa/org/eclipse/swt/widgets/Text.java#L1752-L1782

Perhaps the undo event is being sent on an already disposed widget?

Phillipus commented 3 weeks ago

It seems that the sequence of events that causes the crash is:

  1. Type some text into a Multi Text control
  2. Dispose of the Text control
  3. Press Cmd-Z in another Text control (Single or Multi)

Another Snippet to show this:

import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

public class MacTextControlCrash2 {

    public static void main(String[] args) {
        Display display = new Display();
        Shell shell = new Shell(display);
        shell.setText("Mac Text Control Bug");
        shell.setLayout(new GridLayout());

        Text multiText = new Text(shell, SWT.MULTI | SWT.WRAP);
        GridDataFactory.create(GridData.FILL_BOTH).applyTo(multiText);
        multiText.setText("Type something here and then click the button.");
        multiText.setFocus();

        Button button  = new Button(shell, SWT.PUSH);
        button.setText("Press after typing some text");
        GridDataFactory.create(GridData.FILL_HORIZONTAL).align(SWT.CENTER, SWT.CENTER).applyTo(button);
        button.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent evt) {
                // Dispose of text control
                multiText.dispose();

                button.dispose();

                // Add a new text control
                Text textControl = new Text(shell, SWT.SINGLE);
                GridDataFactory.create(GridData.FILL_BOTH).applyTo(textControl);
                textControl.setText("Now press Cmd-Z for a crash");
                textControl.setFocus();

                shell.layout();
            }
        });

        shell.setSize(300, 250);
        shell.open();

        while(!shell.isDisposed()) {
            if(!display.readAndDispatch()) {
                display.sleep();
            }
        }

        display.dispose();
    }
}
jukzi commented 3 weeks ago

when you see a exception in a foreign library (here: libobjc.A.dylib) - isn't it better to report the issue there (https://github.com/gnustep/libobjc)?

# Problematic frame:
# C  [libobjc.A.dylib+0x9eb0]  lookUpImpOrForward+0x5c
Current thread (0x0000000124808a00):  JavaThread "main" [_thread_in_native, id=259, stack(0x000000016a83c000,0x000000016b038000)]

Stack: [0x000000016a83c000,0x000000016b038000],  sp=0x000000016b02e940,  free space=8138k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C  [libobjc.A.dylib+0x9eb0]  lookUpImpOrForward+0x5c
C  [libobjc.A.dylib+0x9b64]  _objc_msgSend_uncached+0x44
C  [Foundation+0x10f4b8]  -[_NSUndoStack popAndInvoke]+0x74
C  [Foundation+0x10f26c]  -[NSUndoManager undoNestedGroup]+0xc4
C  [libswt-pi-cocoa-4965r11.jnilib+0xe858]  Java_org_eclipse_swt_internal_cocoa_OS_objc_1msgSend__JJ+0x2c
J 825  org.eclipse.swt.internal.cocoa.OS.objc_msgSend(JJ)J (0 bytes) @ 0x00000001161e4840 [0x00000001161e47c0+0x0000000000000080]
C  0x0000000130b8fc27

Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
J 825  org.eclipse.swt.internal.cocoa.OS.objc_msgSend(JJ)J (0 bytes) @ 0x00000001161e4840 [0x00000001161e47c0+0x0000000000000080]
j  org.eclipse.swt.internal.cocoa.NSUndoManager.undo()V+7
Phillipus commented 3 weeks ago

when you see a exception in a foreign library (here: libobjc.A.dylib) - isn't it better to report the issue there (https://github.com/gnustep/libobjc)?

The problem seems to be SWT with NSUndoManager when sending a message to it after a Text control has been disposed. The crash manifests in an Obective-C library because there is a problem with the original message. It may be that some clean-up needs to occur after a Text control is disposed.