Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 537364

Summary: [GTK] DateTime instances leaks in the widgetTable after disposal
Product: [Eclipse Project] Platform Reporter: Andrey Loskutov <loskutov>
Component: SWTAssignee: Andrey Loskutov <loskutov>
Status: RESOLVED FIXED QA Contact:
Severity: normal    
Priority: P3    
Version: 4.5   
Target Milestone: 4.9 M2   
Hardware: PC   
OS: Linux   
See Also: https://bugs.eclipse.org/bugs/show_bug.cgi?id=532632
https://bugs.eclipse.org/bugs/show_bug.cgi?id=394534
https://git.eclipse.org/r/126598
https://git.eclipse.org/c/platform/eclipse.platform.swt.git/commit/?id=6a0d54ebad802fd5044e617494cf7b1e7859edca
https://git.eclipse.org/r/126689
https://git.eclipse.org/c/platform/eclipse.platform.swt.git/commit/?id=41a4facc09ecacf94e62af24583d13dd7ac0789d
Whiteboard:

Description Andrey Loskutov CLA 2018-07-25 04:28:09 EDT
Found during bug 532632 investigations.

DateTime.dispose() leaks disposed DateTime instances in the Display.widgetTable since bug 394534.

This happens because createHandleForDateTime() assigns the same handle to two fields used in register()/deregister() methods:

handle = textEntryHandle;
containerHandle = textEntryHandle;

To reproduce, simply run snippet below. It inspects Display.widgetTable before/after DateTime disposal and throws an assert if after the disposal the widget is still in the widgetTable.

I plan to provide a patch/test for it.

package snippet;

import java.lang.reflect.Field;

import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.DateTime;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Widget;

public class DateTimeLeaks {

	public static void main(String[] args) {
		Display display = new Display();
		Shell shell = createShell(display);
		shell.open();
		
		Widget[] widgetTable = getWidgetTable(display);
		
		Button b = new Button(shell, 0);
		assertExists(widgetTable, b);
		
		DateTime dt = new DateTime(shell, SWT.DATE);
		assertExists(widgetTable, dt);
		
		b.dispose();
		assertNotExists(widgetTable, b);
		
		dt.dispose();
		assertNotExists(widgetTable, dt);
		
		while (!shell.isDisposed()) {
			if (!display.readAndDispatch()) {
				display.sleep();
			}
		}
		display.dispose();
	}
	
	static void assertExists(Widget[] widgetTable, Object o) {
		for (Widget widget : widgetTable) {
			if(widget == o) {
				return;
			}
		}
		throw new AssertionError("Widget table miss: " + o);		
	}
	
	static void assertNotExists(Widget[] widgetTable, Object o) {
		for (Widget widget : widgetTable) {
			if(widget == o) {
				throw new AssertionError("Widget table leaks: " + o);
			}
		}
	}
	
	static Widget[] getWidgetTable(Display display) {
		try {
			Field field = Display.class.getDeclaredField("widgetTable");
			field.setAccessible(true);
			Widget[] widgetTable = (Widget[]) field.get(display);
			return widgetTable;
		} catch (Throwable t) {
			t.printStackTrace();
			return null;
		}
	}
	
	static Shell createShell(Display display) {
		Shell shell = new Shell(display);
		shell.setLayout(new GridLayout());
		shell.setSize(300, 300);
		return shell;
	}

}
Comment 1 Eclipse Genie CLA 2018-07-25 05:07:10 EDT
New Gerrit change created: https://git.eclipse.org/r/126598
Comment 3 Eclipse Genie CLA 2018-07-27 03:37:50 EDT
New Gerrit change created: https://git.eclipse.org/r/126689