JDK-5082481 : normal DnD program causes "FATAL ERROR in native method"
  • Type: Bug
  • Status: Resolved
  • Resolution: Fixed
  • Component: client-libs
  • Sub-Component: java.awt
  • Priority: P4
  • Affected Version: 1.4.2,1.4.2_07
  • OS: windows_xp
  • CPU: x86
  • Submit Date: 2004-08-04
  • Updated Date: 2012-10-09
  • Resolved Date: 2004-09-28
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 Availabitlity Release.

To download the current JDK release, click here.
Other JDK 6
1.4.2_08Resolved 6Resolved
Related Reports
Duplicate :  
Relates :  
Description
Name: js151677			Date: 08/04/2004


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


ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [版本 5.1.2600]

(^^ it is the chinese version of XP)


A DESCRIPTION OF THE PROBLEM :
A simple drag operation on a customized JComponent causes a "FATAL ERROR" when we run the JVM with the option -Xcheck:jni   ... here is the complete error message :

FATAL ERROR in native method: Bad global or local ref passed to JNI
	at sun.awt.windows.WToolkit.eventLoop(Native Method)
	at sun.awt.windows.WToolkit.run(WToolkit.java:262)
	at java.lang.Thread.run(Thread.java:534)

The bug can be reproduced using the "LabelDnD" demo on the page http://java.sun.com/docs/books/tutorial/uiswing/misc/example-1dot4/index.html#LabelDnD

The same bug appear on my reduiced program (that I copy in the "Step to reproduce section")

When I don't use the "-Xcheck:jni" option, my program randomly crash my IDE badly when I am using another native library (jogl), so I think the DnD corrupt the state of the JVM in a way.


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
I have 2 programs that produce the same bug. Here is the first one :


import java.awt.event.*;
import javax.swing.*;

public class BugComponent extends JLabel {

  public BugComponent()
  {
    setText("Drag me and Bug");
    setTransferHandler(new TransferHandler("text"));
    addMouseListener(new MouseAdapter() {
      public void mousePressed(MouseEvent event) {
        JComponent component = (JComponent) event.getSource();
        TransferHandler handler = component.getTransferHandler();
        handler.exportAsDrag(component, event, TransferHandler.COPY);
      }
    });
  }
  
  public static void main(String[] args)
  {
    JFrame f = new JFrame();
    f.getContentPane().add(new BugComponent());
    f.setSize(100, 100);
    f.show();
  }

}



The command line should be :

java -Xcheck:jni BugComponent

.. then, drag the label and the JVM stop and the message :

FATAL ERROR in native method: Bad global or local ref passed to JNI
	at sun.awt.windows.WToolkit.eventLoop(Native Method)
	at sun.awt.windows.WToolkit.run(WToolkit.java:262)
	at java.lang.Thread.run(Thread.java:534)

... is displayed in the console


The other program that produce the same effect is the "LabelDnD" demo from http://java.sun.com/docs/books/tutorial/uiswing/misc/example-1dot4/index.html#LabelDnD


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The JVM should not have any reason to crash. In the worst case (= if the java program is not right), it could be better if an explicit exception were thrown.

ACTUAL -
The DnD causes a FATAL ERROR. If the "-Xcheck:jni" option is not used, the JVM state is corrupted and crash later, sometime, randomly, every 5 minutes of intensive DnD use when using another native library (a GLFrame from jogl).


ERROR MESSAGES/STACK TRACES THAT OCCUR :
FATAL ERROR in native method: Bad global or local ref passed to JNI
	at sun.awt.windows.WToolkit.eventLoop(Native Method)
	at sun.awt.windows.WToolkit.run(WToolkit.java:262)
	at java.lang.Thread.run(Thread.java:534)



REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------

import java.awt.event.*;
import javax.swing.*;

public class BugComponent extends JLabel {

  public BugComponent()
  {
    setText("Drag me and Bug");
    setTransferHandler(new TransferHandler("text"));
    addMouseListener(new MouseAdapter() {
      public void mousePressed(MouseEvent event) {
        JComponent component = (JComponent) event.getSource();
        TransferHandler handler = component.getTransferHandler();
        handler.exportAsDrag(component, event, TransferHandler.COPY);
      }
    });
  }
  
  public static void main(String[] args)
  {
    JFrame f = new JFrame();
    f.getContentPane().add(new BugComponent());
    f.setSize(100, 100);
    f.show();
  }

}



The command line should be :

java -Xcheck:jni BugComponent


---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
None found.
(Incident Review ID: 295664) 
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: 1.5.0_01 mustang FIXED IN: 1.5.0_01 mustang INTEGRATED IN: 1.5.0_01
2004-09-28

EVALUATION Name: ag153227 Date: 08/04/2004 The method AwtDragSource::StartDrag() passes the JNI local reference 'cursor' from one thread to another. It causes the error since local references are only valid in the thread in which they are created. ###@###.### ====================================================================== Name: ag153227 Date: 08/10/2004 This bug is reproducible with mantis and tiger, it isn't reproducible with hopper. It's a regression of the mantis fix 4613903 (Selection changes after a selection is dragged). Passing the JNI reference to another thread was one of effects of that fix. ###@###.### ======================================================================
2004-09-28

SUGGESTED FIX Create a JNI global reference to 'cursor', pass it from one thread to another and delete the global reference after use of it as early as possible. --- awt_DnDDS.cpp Thu Sep 9 14:38:38 2004 *************** *** 66,71 **** --- 66,73 ---- jobject peer = env->NewLocalRef(dragSource->GetPeer()); HCURSOR initialCursor = dragSource->SetCursor(sdrp->cursor); + env->DeleteGlobalRef(sdrp->cursor); + HRESULT res; // StartDrag has caused dragSource->m_mutex to be held by our thread now *************** *** 1539,1544 **** --- 1541,1548 ---- JNIEXPORT void JNICALL Java_sun_awt_windows_WDragSourceContextPeer_doDragDrop(JNIEnv* env, jobject self, jlong nativeCtxt, jobject cursor) { TRY; + cursor = env->NewGlobalRef(cursor); + AwtDragSource::StartDrag((AwtDragSource*)nativeCtxt, cursor); CATCH_BAD_ALLOC; ###@###.### 2004-09-09 The previous fix is tricky: if the global reference 'sdrp->cursor' were deleted somewhere in the end of the method _DoDragDrop(), there could be another JNI error since 'sdrp' is an address of a struct allocated on the stack of the method StartDrag() and the method StartDrag() returns. Now, to make the code more straightforward, the struct is allocated in the heap instead of the stack: --- awt_DnDDS.cpp Thu Sep 9 16:53:44 2004 *************** *** 45,55 **** */ void AwtDragSource::StartDrag(AwtDragSource* self, jobject cursor) { ! StartDragRec sdr = {self, cursor}; AwtToolkit::GetInstance().WaitForSingleObject(self->m_mutex); ! AwtToolkit::GetInstance().InvokeFunctionLater((void (*)(void *))&AwtDragSource::_DoDragDrop, (void *)&sdr); self->WaitUntilSignalled(FALSE); } --- 45,57 ---- */ void AwtDragSource::StartDrag(AwtDragSource* self, jobject cursor) { ! StartDragRec* sdrp = new StartDragRec; ! sdrp->dragSource = self; ! sdrp->cursor = cursor; AwtToolkit::GetInstance().WaitForSingleObject(self->m_mutex); ! AwtToolkit::GetInstance().InvokeFunctionLater((void (*)(void *))&AwtDragSource::_DoDragDrop, (void *)sdrp); self->WaitUntilSignalled(FALSE); } *************** *** 66,71 **** --- 68,76 ---- jobject peer = env->NewLocalRef(dragSource->GetPeer()); HCURSOR initialCursor = dragSource->SetCursor(sdrp->cursor); + env->DeleteGlobalRef(sdrp->cursor); + delete sdrp; + HRESULT res; // StartDrag has caused dragSource->m_mutex to be held by our thread now *************** *** 1539,1544 **** --- 1544,1551 ---- JNIEXPORT void JNICALL Java_sun_awt_windows_WDragSourceContextPeer_doDragDrop(JNIEnv* env, jobject self, jlong nativeCtxt, jobject cursor) { TRY; + cursor = env->NewGlobalRef(cursor); + AwtDragSource::StartDrag((AwtDragSource*)nativeCtxt, cursor); CATCH_BAD_ALLOC; ###@###.### 2004-09-09
2004-09-09