JDK-4713003 : 1.4.1 REGRESSION: Windows XP freezes on Java application exit/draw
  • Type: Bug
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 1.2.0,1.4.1,1.4.1_01
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_98,windows_2000,windows_xp
  • CPU: x86
  • Submitted: 2002-07-10
  • Updated: 2002-12-06
  • Resolved: 2002-11-12
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other Other
1.4.1_02 02Fixed 1.4.2Fixed
Related Reports
Duplicate :  
Duplicate :  
Duplicate :  
Duplicate :  
Duplicate :  
Duplicate :  
Relates :  
Description

Name: jk109818			Date: 07/10/2002


FULL PRODUCT VERSION :
java version "1.4.1-beta"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1-beta-b14)
Java HotSpot(TM) Client VM (build 1.4.1-beta-b14, mixed mode)

FULL OPERATING SYSTEM VERSION :
Microsoft Windows XP [Version 5.1.2600]

EXTRA RELEVANT SYSTEM CONFIGURATION :
ATI Radeon AGP graphics card 7200
Driver: ati2dvag.dll ver: 6.13.10.6071 (English)
DirectX 8.1 (4.08.01.0810)

A DESCRIPTION OF THE PROBLEM :
Windows XP freezes (hangs) on Java application exit. I
experience this consistantly on all applications that take
advantage of image drawing functions. I have not been able
to reproduce on other Java applications. Application runs
fine but Windows XP freezes indefinitely on exit. Once
while running an application using drawImage() to a panel
I entered a Windows blue screen complaining of an infinite
loop in the video driver. Sometimes the program will exit
normally if you simply start and exit with small drawing
activity, but a reasonable amount of image drawing
activity seems to cause Windows XP to hang on exit. While
difficult to pinpoint (since you are left with no errors
while your machine reboots), it is probably due to a new
incompatibility between the java runtime and video driver.
I do not have this problem with any JDK previous to the
1.4.1 beta release.

REGRESSION.  Last worked in version 1.4

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Compile and run attached program (or any other java
application with sufficient image placement activity).
2. Select "Open Image..." from the File menu and select a
*.jpg format image that would fit onscreen at full size.
For example, a 640 x 480 image is fine.
3. Click on different locations of the loaded image to
scramble the 'pieces', observing that the draw
functionality is working. Scramble the image pieces, as
this seems to be the source of the freeze on application
exit.
4. Exit the application and watch Windows freeze.

EXPECTED VERSUS ACTUAL BEHAVIOR :
Java runtime should gracefully exit, as it almost always
has on previous releases of the JVM. Instead, Java appears
to be the cause of Windows freezing on exit.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
There are no error messages, nor output from the JVM.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
package scratch;
// Freeze.java	William Dubel	June 30, 2003

import java.io.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.ArrayList;
import java.util.Collections;
import javax.swing.border.TitledBorder;

public class Freeze extends JFrame  {
	private JMenuItem newGame, quit, about;
	private JMenu fileMenu;
	private JPanel puzzleArea, puzzleGrid;
	private JMenuBar bar;
	private JFileChooser fileChooser = new JFileChooser();
	private Container c;
	private int tiles = 25;
	private ArrayList pieces = new ArrayList();
	private Game currentGame;
	private MouseHandler mouseHandler = new MouseHandler();
	private ItemHandler itemHandler = new ItemHandler();

	public Freeze() {
		super("ImageTest");
		c = getContentPane();

		fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);

		setJMenuBar(bar = new JMenuBar());
		(fileMenu = new JMenu("File")).setMnemonic('F');
		(newGame = new JMenuItem("Open
Image...",'N')).addActionListener(itemHandler);
		(quit = new JMenuItem("Exit",'x')).addActionListener
(itemHandler);
		fileMenu.add(newGame);
		fileMenu.add(quit);
		bar.add(fileMenu);

		(puzzleGrid = new JPanel()).setLayout(new GridLayout(1, 1));
		puzzleGrid.setSize(300,300);

		(puzzleArea = new JPanel()).setLayout(new FlowLayout());
		puzzleArea.add(puzzleGrid);
		puzzleArea.setBorder(new TitledBorder("Click on image to
scramble"));

		c.add(puzzleArea,BorderLayout.CENTER);
		setSize(500,400);

		addWindowListener( new WindowAdapter()	{
			public void windowClosing( WindowEvent e ) {
				System.exit(0);
			}
		}   );
	}

	private class MouseHandler extends MouseAdapter {
		private int first = -1;
		public void mousePressed(MouseEvent e)  {
			if (first<0 || first >= tiles)  {
				for (int n=0; n<tiles; n++) if (e.getSource()
==pieces.get(n))
				{
					((Piece)pieces.get(first =
n)).setSelected(true);
					((Piece)pieces.get(first)).repaint();
				}
			}
			else    {
				for (int n=0; n<tiles; n++)
					if (e.getSource()==pieces.get(n))   {
						((Piece)pieces.get(n)).repaint
();
						((Piece)pieces.get
(first)).setSelected(false);

						puzzleGrid.removeAll();
						Collections.swap(pieces,
first, n);

						for (int i=0; i<tiles; i++)
puzzleGrid.add((Piece)pieces.get(i));
						puzzleGrid.validate();
					}
				first = -1;
			}
		}
	}

	private class ItemHandler implements ActionListener {
		public void actionPerformed( ActionEvent e )    {
			if (e.getSource()==newGame) {
				int answer = -1;
				if (answer!=JOptionPane.CANCEL_OPTION)  {
					int result = fileChooser.showOpenDialog
(c);
					if (result!
=JFileChooser.CANCEL_OPTION) {
						File filename =
fileChooser.getSelectedFile();

						currentGame = new Game
((filename), tiles);

						puzzleArea.remove(puzzleGrid);
						puzzleGrid = new JPanel();
						puzzleGrid.setLayout(new
GridLayout(currentGame.getRows(), currentGame.getCols()));

						pieces = new ArrayList();
						for (int i=0; i<tiles; i++) {
							Piece temp = new Piece
(currentGame, i+1);
							temp.addMouseListener
(mouseHandler);
							pieces.add(temp);
							puzzleGrid.add(temp);
						}
						puzzleGrid.setSize(	(int)
currentGame.getSize().getWidth(),
									
				(int)currentGame.getSize().getHeight()	);
						puzzleArea.add(puzzleGrid);
						pack();
						puzzleGrid.validate();
					}
				}
			}
			if (e.getSource()==quit)        {       System.exit
(0);         }
		}
	}

	public static void main(String [] args) {
		JFrame puzzlegame = new Freeze();
		puzzlegame.setVisible(true);
	}
}

class Game  {
	private ImageIcon imageObject;
	private int complexity;

	public Game(File filename, int complexity)  {
		this.complexity = complexity;
		imageObject = new ImageIcon(filename.getPath());
		try	{ while (imageObject.getImageLoadStatus()
==MediaTracker.LOADING) Thread.sleep(10); }
		catch(InterruptedException ie)	{	ie.printStackTrace();
				}
	}

	public Image getImage()					{	return
imageObject.getImage();	}

	public Dimension getSize()				{
		return new Dimension(imageObject.getIconWidth
(),imageObject.getIconHeight());
	}

	public int getRows()	{
		return (int)Math.sqrt(complexity);
	}

	public int getCols()	{
		return getRows();
	}
}

class Piece extends JPanel implements Runnable  {
	private Dimension size;
	private Image mini;
	private int order;
	private MediaTracker loader;
	private boolean selected = false;

	public Piece(Game currentGame, int tile)    {
		size = new Dimension((int)(currentGame.getSize().getWidth
()/currentGame.getCols()),
									(int)
(currentGame.getSize().getHeight()/currentGame.getRows()));
		mini = currentGame.getImage();

		CropImageFilter cropFilter =
			new CropImageFilter(	(((tile%currentGame.getCols()!
=0) ? tile%currentGame.getCols()
									
		: currentGame.getCols())-1)*(int)size.getWidth(),

									
	(int)((Math.ceil((double)tile/currentGame.getCols())-1)*size.getHeight
()),
									
	(int)size.getWidth(),
									
	(int)size.getHeight());

		mini = createImage(new FilteredImageSource(mini.getSource
(),cropFilter));
		order = tile;

		loader = new MediaTracker(this);
		loader.addImage(mini, order);
		new Thread(this).start();
	}

	public void run()   {
		try
		{	while (loader.statusID(order, true)!
=MediaTracker.COMPLETE) Thread.sleep(20);	}
		catch(InterruptedException ie)		{
	ie.printStackTrace();		}
		repaint();
	}

	public Dimension getPreferredSize()		{		return
size;				}
	public boolean isSelected()				{
	return selected;			}
	public void setSelected(boolean yes)	{		selected = yes;
			    }

	public void paintComponent(Graphics g)  {
		Graphics2D g2 = (Graphics2D)g;

		if (loader.statusID(order, true)!=MediaTracker.COMPLETE)    {
			GradientPaint gp = new GradientPaint(0.0f, 0.0f,
Color.lightGray,
				   (float)size.getWidth(), (float)
size.getHeight(), Color.darkGray);
			g2.setPaint(gp);
			g2.fillRect(0, 0, (int)size.getWidth()-1, (int)
size.getHeight()-1);
		}
		else    {
			g2.drawImage(mini, 0, 0, (int)size.getWidth(), (int)
size.getHeight(), this);
			if (selected)
			{
				g2.draw3DRect(1, 1, (int)size.getWidth()-3,
(int)size.getHeight()-3, false);
				g2.draw3DRect(0, 0, (int)size.getWidth()-1,
(int)size.getHeight()-1, false);
			}
		}
	}
}
---------- END SOURCE ----------

Release Regression From : hopper-beta
The above release value was the last known release where this 
bug was known to work. Since then there has been a regression.

(Review ID: 158715) 
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: 1.4.1_02 mantis FIXED IN: 1.4.1_02 mantis INTEGRATED IN: 1.4.1_02 mantis mantis-b07
14-06-2004

PUBLIC COMMENTS .
10-06-2004

EVALUATION Still can't reproduce this problem. Targetting it for mantis. This seems very card-specific. We have tried it on very similar platforms, including XP with the Radeon 7200 VE (a variation on the 7200 that lacks the geometry engine) and have still not seen the crash here. We need to pick up the exact same card and see if that helps reproduce the problem. The user has only seen the problem on the one machine with this configuration, although they did test with 2 different drivers (the original XP driver as well as a more recent ATI driver) and both drivers produced the bug. ###@###.### 2002-07-23 The user does not experience the freeze when running with the noddraw flag. It is also worth trying the sun.java2d.d3d=false flag (but the user needs a later build past the 1.4.1 b14 build they are running with now to try this flag). ###@###.### 2002-07-23 I am finally able to reproduce this problem. I installed a Radeon 7500 with driver version 5.13.1.6043 and I now get either a hang or a Blue Screen Of Death upon app exit. Note the workarounds: both the noddraw=true and d3d=false flags prevent the problem from occurring. Thus the problem must be somewhere in our d3d usage. One strange thing I noticed during my debugging so far was that the creation of d3d devices fails with the error E_NOINTERFACE (0x80004002). This is curious for two reasons: - I don't know why we would fail, or why failing that call (CreateDevice) would fail with that error (it is not even spec'd to return that error). - Since we fail creating the device, we should not be using d3d to render anything (lpSurface for those DDrawSurface objects is NULL). So there should be very little interaction with d3d that gets us into trouble (except, presumably, these calls to CreateDevice). ###@###.### 2002-08-29 The error I was getting above (E_NOINTERFACE) was erroneous; this was actually an error I was getting when trying to create a d3d device on my secondary device when running multimon. Since that other device is a Matrox Mill II, which does not support d3d, getting an error during d3d device creation is not too surprising. I disabled my second monitor to reduce the confusion and still consistently blue-screen upon app exit. I no longer get any ddraw/d3d errors during device creation (or at any other time). And I can step, using the debugger, all the way through the exit from DllMain during PROCESS_DETACH, so there is nothing obvious that is causing this problem. Presumably we are trouncing on memory somewhere, but I don't have any leads yet. It is worth trying to reproduce this problem in a native app to narrow it down. ###@###.### 2002-09-03 I have attached a test case which is a purely native app that shows the problem. Apparently the problem is that we create too many d3d devices. Currently, whenever we want d3d capabilities on a ddraw surface, we create a d3d device for that surface. The DirectX docs suggest that having one d3d device per ddraw object (not per ddraw surface) is a better way to go for performance reasons; the context switching inherent in multiple d3d devices is too expensive. They do not happen to mention that having too many devices can also hang the system (this is presumably a driver bug that we just happened to bump into on these ATI boards). Although the real fix for the crash lies with ATI (I don't think the OS should crash because of what we are doing), we can and should fix the problem in our code by moving to a system of sharing a single d3d device, as suggested by the DirectX documention. There are issues with this approach, such as: - we need to do a SetRenderTarget whenever we are rendering into a new ddraw surface since the single d3d device may currently be set to a different render target. - in addition to changing the rendering target, we also need to update the viewport if the dimensions of the new surface differ from the previous one. - we need to lock around accesses to this shared device since we have potential multi-threaded rendering issues when rendering to different surfaces. The test case (4713003.ManyD3dDevices.zip.Z) is a zipped project file from a DevStudio application. You can either run the app in the Debug folder directly or build the application and run it within DevStudio. By changing the "NUM_OFFSCREEN_SURFACES" variable at the top of DDHelloWorld.cpp you can affect the crash. I found that the crash only occurred when this value was greater than 8 (the value is currently set to 9 in that file). Forwarding the bug to the engineer currently working on the single-device approach. ###@###.### 2002-09-06
06-09-2002

WORK AROUND Use -Dsun.java2d.noddraw=true This prevents our use of DirectX for rendering and apparently (according to the submitter) avoids whatever the freeze problem is. The flag -Dsun.java2d.d3d=false is also worth trying (and a better, less constraining flag to use), but the user has not yet been able to verify whether this avoids the bug since the publicly release build is currently b14, which does not yet fully implement the d3d=false functionality. ###@###.### 2002-07-23 -Dsun.java2d.d3d=false doesn't avoid the problem with 1.4.1-beta-b14. However, this option helps to avoid problem with 1.4.1_01-bo1. ###@###.### 2002-10-31
23-07-2002