JDK-4947550 : Null Pointer in creating Window
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 1.3.1_09
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_2000
  • CPU: x86
  • Submitted: 2003-11-03
  • Updated: 2004-09-16
  • Resolved: 2003-12-18
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.3.1_11 11Fixed 1.4.2_04Fixed
Description
Customer is seeing a NPE.
Error: java.lang.NullPointerException
        at java.awt.Window.<init>(Window.java:197)
        at java.awt.Frame.<init>(Frame.java:310)
        at java.awt.Frame.<init>(Frame.java:257)
        at com.epiphany.charts.roguewave.ChartFactory.getGIFRepresentation(ChartFactory.java:209)
        at com.epiphany.charts.roguewave.ChartFactory.createChart(ChartFactory.java:271)
        at com.epiphany.charts.CreateChartAction.execute(CreateChartAction.java:111)
        at com.epiphany.server.CommandThread.execute(CommandThread.java:301)
        at com.epiphany.server.CommandThread.runInternal(CommandThread.java:160)
        at com.epiphany.server.EpiThread.run(EpiThread.java:96)
###@###.### 2003-11-03

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: 1.3.1_11 1.4.2_04 generic tiger-beta FIXED IN: 1.3.1_11 1.4.2_04 tiger-beta INTEGRATED IN: 1.3.1_11 1.4.2_04 tiger-b32 tiger-beta
17-09-2004

SUGGESTED FIX *** /home/bchristi/jano2/bchristi/tiger/webrev/src/windows/native/sun/windows/awt_Win32GraphicsConfig.cpp- Fri Nov 7 15:26:57 2003 --- awt_Win32GraphicsConfig.cpp Fri Nov 7 15:25:21 2003 *** 79,90 **** if( TRUE == ::MonitorBounds(AwtWin32GraphicsDevice::GetMonitor(screen), &rRW) ) { bounds = env->NewObject(clazz, mid, rRW.left, rRW.top, rRW.right - rRW.left, rRW.bottom - rRW.top); if (safe_ExceptionOccurred(env)) { return 0; } } - } return bounds; } --- 79,98 ---- if( TRUE == ::MonitorBounds(AwtWin32GraphicsDevice::GetMonitor(screen), &rRW) ) { bounds = env->NewObject(clazz, mid, rRW.left, rRW.top, rRW.right - rRW.left, rRW.bottom - rRW.top); + } + else { + // 4910760 - don't return a null bounds, return the bounds of the + // primary screen + bounds = env->NewObject(clazz, mid, + 0, 0, + ::GetSystemMetrics(SM_CXSCREEN), + ::GetSystemMetrics(SM_CYSCREEN)); + } if (safe_ExceptionOccurred(env)) { return 0; } } return bounds; } *** /home/bchristi/jano2/bchristi/tiger/webrev/src/windows/native/sun/windows/awt_Win32GraphicsEnv.cpp- Fri Nov 7 15:26:58 2003 --- awt_Win32GraphicsEnv.cpp Thu Nov 6 18:32:01 2003 *** 96,106 **** for (int i = 0; i < awt_numScreens; i++) { if (areSameMonitors(mon, getMHNDFromScreen(i))) { return i; } } ! return -1; } /* * Class: sun_awt_Win32GraphicsEnvironment * Method: initDisplay --- 96,107 ---- for (int i = 0; i < awt_numScreens; i++) { if (areSameMonitors(mon, getMHNDFromScreen(i))) { return i; } } ! DTRACE_PRINTLN("getScreenFromMHND(): couldn't find screen, return default"); ! return AwtWin32GraphicsDevice::GetDefaultDeviceIndex(); } /* * Class: sun_awt_Win32GraphicsEnvironment * Method: initDisplay ###@###.### 2003-11-25
25-11-2003

EVALUATION Reproducible as described. ###@###.### 2003-11-04 Leaving a Java app running, locking the remote machine, disconnecting, and then reconnecting was not a problem with a "normal" app, such as SwingSet or Java2Demo. The test case, though, boils down to: while(weHaven'tDiedYet) { Frame f = new Frame(); f.pack(); f.dispose(); } So, even after disconnecting, the test will still (try to) create native backing windows. The NPE comes from this swatch of code in Window.java: Rectangle screenBounds = graphicsConfig.getBounds(); Insets screenInsets = getToolkit().getScreenInsets(graphicsConfig); ---> int x = getX() + screenBounds.x + screenInsets.left; int y = getY() + screenBounds.y + screenInsets.top; screenBounds is coming up null, and we NPE on the indicated line. Here's where the null comes from: Java_sun_awt_Win32GraphicsConfig_getBounds(JNIEnv *env, jobject thisobj, jint screen) { ... jobject bounds = NULL; ... if( TRUE == ::MonitorBounds(AwtWin32GraphicsDevice::GetMonitor(screen), &rRW) ) { bounds = env->NewObject(clazz, mid, rRW.left, rRW.top, rRW.right - rRW.left, rRW.bottom - rRW.top); ... } ... return bounds; } ::MonitorBounds fails, presumably because our cached MHND is no longer valid after we disconnect from the remote session. bounds remains NULL, and is returned as such. The customer works around this in their JDK by not using screenBounds if it's null (see the Work Around). This may work with 1.3.1_09 and/or 1.4.2_02 (I didn't try), but I've found that with 1.5 it turns ths exception into a crash. ;( The crash comes when AwtComponent::SetBackgroundColor() tries to use an array index of -1. Observe: void AwtComponent::SetBackgroundColor(COLORREF c) { int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(GetHWnd()); int grayscale = AwtWin32GraphicsDevice::GetGrayness(screen); if (grayscale != GS_NOTGRAY) { ... The basic idea is to get from AwtComponent to grayness via: HWND->MHND->index into our array of devices->grayness of the device at that index. The HWND->MHND step is done by the win32 function ::MonitorFromWindow() called from AwtWin32GraphicsDevice::DeviceIndexForWindow(). The MHND->index step is done by getScreenFromMHND() in awt_Win32GraphicsEnv.cpp. So, we get the MHND for our HWND, and look through our cached AwtWin32GraphicsDevices for that MHND: int getScreenFromMHND(MHND mon) { DASSERT(mon != NULL); for (int i = 0; i < awt_numScreens; i++) { if (areSameMonitors(mon, getMHNDFromScreen(i))) { return i; } } return -1; } HOWEVER When we disconnect from the remote server, ::MonitorFromWindow() starts returning MHNDs we've never seen. I assume it does some sort of display change. At any rate, getScreenFromMHND() nevers finds it, and returns -1. At first I thought that this problem might be addressed by fixing: 4417798 : Need to track add/remove of monitors on display changes but from my debugging statements it looks like the crash happens before we see the WM_DISPLAYCHANGE. event. My fix has two parts: 1) Return the bounds of the primary monitor from Win32GraphicsConfig.getBounds() instead of null in the case that ::MonitorBounds() fails. This prevents the NPE in Window.java (and anywhere else that might call GC.getBounds()). 2) Return default idx (usually 0) instead of -1 from getScreenFromMHND() This keeps things running, though in a bit of a weird state, since without 4417798 our AwtWin32GraphicsDevice array is never updated. But it doesn't NPE or crash. ###@###.### 2003-11-25
25-11-2003

WORK AROUND As screenBounds is null, here is what customer changed in Window.java to workaround the problem: The change is in the java.awt.Window class, within the Window(GraphicsConfiguration gc) constructor. /* offset the initial location with the original of the screen */ Rectangle screenBounds = graphicsConfig.getBounds(); int x = getX() + screenBounds.x; int y = getY() + screenBounds.y; setLocation(x, y); becomes /* offset the initial location with the original of the screen */ Rectangle screenBounds = graphicsConfig.getBounds(); if (screenBounds != null) { int x = getX() + screenBounds.x; int y = getY() + screenBounds.y; setLocation(x, y); } else { setLocation(getX(), getY()); } ###@###.### 2003-11-03
03-11-2003