Bug 577192 - Eclipse/SWT crashs in gc.fillRectangle on MacOS
Summary: Eclipse/SWT crashs in gc.fillRectangle on MacOS
Status: NEW
Alias: None
Product: Platform
Classification: Eclipse Project
Component: SWT (show other bugs)
Version: 4.22   Edit
Hardware: PC Mac OS X
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Platform-SWT-Inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2021-11-10 09:57 EST by Stephan Wahlbrink CLA
Modified: 2023-05-26 11:57 EDT (History)
1 user (show)

See Also:


Attachments
Minimal SWT application to reproduce the crash (2.23 KB, application/octet-stream)
2021-11-10 09:57 EST, Stephan Wahlbrink CLA
no flags Details
sysout of the crash (1.01 KB, text/plain)
2021-11-10 09:59 EST, Stephan Wahlbrink CLA
no flags Details
crash report (82.51 KB, text/plain)
2021-11-10 10:00 EST, Stephan Wahlbrink CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Stephan Wahlbrink CLA 2021-11-10 09:57:38 EST
Created attachment 287479 [details]
Minimal SWT application to reproduce the crash

Eclipse/SWT crashs reproducible in gc.fillRectangle and similar methods on MacOS if called in a sequence like this:

var image= new Image(display, imageWidth, imageHeigth);
var gc= new GC(this.image);
image.getImageData();
// idle / readAndDispatch
gc.fillRectangle(0, 0, imageWidth, imageHeigth);

See attached java class for a full minimal SWT application showing the issue.

Tested with org.eclipse.swt_3.118.0.v20211022-2202
Comment 1 Stephan Wahlbrink CLA 2021-11-10 09:59:22 EST
Created attachment 287480 [details]
sysout of the crash
Comment 2 Stephan Wahlbrink CLA 2021-11-10 10:00:03 EST
Created attachment 287481 [details]
crash report
Comment 3 Phil Beauvoir CLA 2021-11-10 11:39:41 EST
I can reproduce your crash on Catalina, Big Sur and Monterey with Temurin Java 11.0.13+8 on x86_64, but not on Big Sur on Mac M1 (aarch64) with Zulu Java 11.0.13+8 where the snippet runs fine.
Comment 4 Eclipse Genie CLA 2021-11-13 06:52:24 EST
New Gerrit change created: https://git.eclipse.org/r/c/statet/org.eclipse.statet-rj/+/187711
Comment 5 Dan Moldoveanu CLA 2023-05-26 04:22:17 EDT
(In reply to Stephan Wahlbrink from comment #0)
> Created attachment 287479 [details]
> Minimal SWT application to reproduce the crash
> 
> Eclipse/SWT crashs reproducible in gc.fillRectangle and similar methods on
> MacOS if called in a sequence like this:
> 
> var image= new Image(display, imageWidth, imageHeigth);
> var gc= new GC(this.image);
> image.getImageData();
> // idle / readAndDispatch
> gc.fillRectangle(0, 0, imageWidth, imageHeigth);
> 
> See attached java class for a full minimal SWT application showing the issue.
> 
> Tested with org.eclipse.swt_3.118.0.v20211022-2202

Hi Stephan,

I encountered this too - is there any solution/workaround for this bug?

Thanks! :D
Comment 6 Stephan Wahlbrink CLA 2023-05-26 05:51:52 EDT
(In reply to Dan Moldoveanu from comment #5)
> I encountered this too - is there any solution/workaround for this bug?

If it is your code: avoid such code sequences, e.g. always recreate the GC after idle / readAndDispatch (
in our project: https://gitlab.eclipse.org/eclipse/statet/statet/-/blob/b80043cc2e1b347284f3f48067cfe055a51cab1e/rj.eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/FontManager.java#L642)

If it is not your code: no.
Comment 7 Dan Moldoveanu CLA 2023-05-26 06:54:57 EDT
(In reply to Stephan Wahlbrink from comment #6)
> (In reply to Dan Moldoveanu from comment #5)
> > I encountered this too - is there any solution/workaround for this bug?
> 
> If it is your code: avoid such code sequences, e.g. always recreate the GC
> after idle / readAndDispatch (
> in our project:
> https://gitlab.eclipse.org/eclipse/statet/statet/-/blob/
> b80043cc2e1b347284f3f48067cfe055a51cab1e/rj.eclient/org.eclipse.statet.rj.
> eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/
> FontManager.java#L642)
> 
> If it is not your code: no.

I have this GC below - do you have any ideas on how can I recreate the GC? The problem is that it is inside a new Thread and I cannot re-instantiate the 'shellGC' variable.
Would appreciate any help! Thanks alot! :)

https://pastebin.com/VqwGaW4s

(manually pasted here also)
private void createAnimationThread(int gifSize) {
		Display display = parent.getDisplay();
		GC shellGC = new GC(this);
		Color shellBackground = getBackground();

		animateThread = new Thread() {
			@Override
			public void run() {
				/*
				 * Create an off-screen image to draw on, and fill it with the shell background.
				 */
				Image offScreenImage = new Image(display, loader.logicalScreenWidth, loader.logicalScreenHeight);
				GC offScreenImageGC = new GC(offScreenImage);
				offScreenImageGC.setBackground(shellBackground);
				offScreenImageGC.fillRectangle(0, 0, loader.logicalScreenWidth, loader.logicalScreenHeight);

				try {
					/*
					 * Create the first image and draw it on the off-screen image.
					 */
					int imageDataIndex = 0;
					ImageData imageData = imageDataArray[imageDataIndex];
					if (image != null && !image.isDisposed())
						image.dispose();
					image = new Image(display, imageData);
					offScreenImageGC.drawImage(image, 0, 0, imageData.width, imageData.height,
							(imageData.width - gifSize) / 2, (imageData.height - gifSize) / 2, gifSize, gifSize);

					/*
					 * Now loop through the images, creating and drawing each one on the off-screen
					 * image before drawing it on the shell.
					 */
					while (!stopAnimation) {
						switch (imageData.disposalMethod) {
						case SWT.DM_FILL_BACKGROUND:
							/*
							 * Fill with the background color before drawing.
							 */
							Color bgColor = null;
							offScreenImageGC.setBackground(bgColor != null ? bgColor : shellBackground);
							offScreenImageGC.fillRectangle(imageData.x, imageData.y, imageData.width, imageData.height);
							break;
						case SWT.DM_FILL_PREVIOUS:
							/*
							 * Restore the previous image before drawing.
							 */
							offScreenImageGC.drawImage(image, 0, 0, imageData.width, imageData.height,
									(imageData.width - gifSize) / 2, (imageData.height - gifSize) / 2, gifSize,
									gifSize);
							break;
						}

						imageDataIndex = (imageDataIndex + 1) % imageDataArray.length;
						imageData = imageDataArray[imageDataIndex];
						if (image != null && !image.isDisposed()) {
							image.dispose();
						}
						image = new Image(display, imageData);
						offScreenImageGC.drawImage(image, 0, 0, imageData.width, imageData.height,
								(imageData.width - gifSize) / 2, (imageData.height - gifSize) / 2, gifSize, gifSize);

						/*
						 * Draw the off-screen image
						 */

						display.syncExec(new Runnable() {
							@Override
							public void run() {
								if (LoadingComposite.this.isDisposed()) {
									return;
								}

								Point point = LoadingComposite.this.getSize();

								int xPos = (point.x - offScreenImage.getBounds().width) / 2;

								int yPos;
								switch (loadingPosition) {
								case CENTER:
									yPos = (point.y - offScreenImage.getBounds().height) / 2;
									break;
								case TOP:
									yPos = 0 + offScreenImage.getBounds().height / 4;
									break;
								case BOTTOM:
									yPos = point.y - offScreenImage.getBounds().height;
									break;
								default:
									yPos = 0;
								}

								
								if (shellGC != null && !shellGC.isDisposed()) { 
									shellGC.dispose(); 
									//how to recreate it here?
								}								 

								shellGC.fillRectangle(0, 0, point.x, point.y);
								shellGC.drawImage(offScreenImage, xPos, yPos);
							}
						});

						/*
						 * Sleep for the specified delay time (adding commonly-used slow-down fudge
						 * factors).
						 */
						try {
							int ms = imageData.delayTime * 10;
							if (ms < 20)
								ms += 30;
							if (ms < 30)
								ms += 10;
							Thread.sleep(ms);
						} catch (InterruptedException e) {
						}
					}
				} catch (SWTException ignored) {
					// Assuming thread was stopped because component was
					// disposed
				} finally {
					if (offScreenImage != null && !offScreenImage.isDisposed())
						offScreenImage.dispose();
					if (offScreenImageGC != null && !offScreenImageGC.isDisposed())
						offScreenImageGC.dispose();
					if (image != null && !image.isDisposed())
						image.dispose();
				}
			}
		};

		animateThread.setDaemon(true);
		animateThread.start();
	}
Comment 8 Dan Moldoveanu CLA 2023-05-26 09:43:09 EDT
(In reply to Stephan Wahlbrink from comment #6)
> (In reply to Dan Moldoveanu from comment #5)
> > I encountered this too - is there any solution/workaround for this bug?
> 
> If it is your code: avoid such code sequences, e.g. always recreate the GC
> after idle / readAndDispatch (
> in our project:
> https://gitlab.eclipse.org/eclipse/statet/statet/-/blob/
> b80043cc2e1b347284f3f48067cfe055a51cab1e/rj.eclient/org.eclipse.statet.rj.
> eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/
> FontManager.java#L642)
> 
> If it is not your code: no.

I initialized the GC locally and after using it, I disposed it and it seems to work now.
Now that I figured it out how to make it not crash the whole eclipse IDE, my GC is not drawing anything (on macOS still) - any clue if I solved the previous problem correctly or how should it be done? Thanks!

I need the syncExec for loading a GIF image (but I added fillRectangle for testing purposes)

display.syncExec(new Runnable() {
	@Override
	public void run() {
		if (LoadingComposite.this.isDisposed()) {
			return;
		}

		GC shellGC = new GC(LoadingComposite.this); 
		
		shellGC.setBackground(new Color(255, 0, 0));
		shellGC.fillRectangle(0, 0, 200, 200); //does not fill it on macOS (works fine on windows)
		shellGC.dispose();
	}
});
Comment 9 Alexander Kurtakov CLA 2023-05-26 09:46:18 EDT
SWT development moved to using Github Issues a year or so ago https://github.com/eclipse-platform/eclipse.platform.swt and I doubt anyone is really following old bugzilla issues anymore. I got this one for historical reasons only. 
So please open issue at https://github.com/eclipse-platform/eclipse.platform.swt if you want to get attention from someone.
Comment 10 Dan Moldoveanu CLA 2023-05-26 09:50:13 EDT
(In reply to Alexander Kurtakov from comment #9)
> SWT development moved to using Github Issues a year or so ago
> https://github.com/eclipse-platform/eclipse.platform.swt and I doubt anyone
> is really following old bugzilla issues anymore. I got this one for
> historical reasons only. 
> So please open issue at
> https://github.com/eclipse-platform/eclipse.platform.swt if you want to get
> attention from someone.

I opened one there as well, but I saw that here Stephan responded quicker and it was also helpful :) 
I hoped that I can get some more help from him that's why I continued this thread 😅