United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-5082481 : normal DnD program causes "FATAL ERROR in native method"

Details
Type:
Bug
Submit Date:
2004-08-04
Status:
Resolved
Updated Date:
2012-10-09
Project Name:
JDK
Resolved Date:
2004-09-28
Component:
client-libs
OS:
windows_xp
Sub-Component:
java.awt
CPU:
x86
Priority:
P4
Resolution:
Fixed
Affected Versions:
1.4.2,1.4.2_07
Fixed Versions:
5.0u1 (01)

Related Reports
Backport:
Backport:
Duplicate:
Relates:

Sub Tasks

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
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
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
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



Hardware and Software, Engineered to Work Together