-
Bug
-
Resolution: Fixed
-
P4
-
1.3.0
-
ladybird
-
x86
-
windows_nt
-
Not verified
Issue | Fix Version | Assignee | Priority | Status | Resolution | Resolved In Build |
---|---|---|---|---|---|---|
JDK-2034568 | 1.4.0 | Tim Bell | P4 | Resolved | Fixed | beta |
Name: rlT66838 Date: 06/02/2000
java version "1.3.0rc3"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0rc3-Z)
Java HotSpot(TM) Client VM (build 1.3.0rc3-Z, mixed mode)
I encountered a problem using the JPDA example to attach to a running VM.
I downloaded jpda1_0-win.zip.
I run my test program, which opens a window and waits for a close event, from
one console window:
D:> java -classpath d:\jd\work -Djava.compiler=NONE -Xnoagent -Xdebug -
Xrunjdwp:transport=dt_shmem,server=y,suspend=n Simple
Java HotSpot(TM) Client VM warning: Setting of property "java.compiler" is
ignored
Listening for transport dt_shmem at address: javadebug
In another console window, I compiled the example provided (package tty) in the
jpda1_0-examples.zip file and ran TTY:
C:\jpda\examples\debuggers>d:\jdk1.3\bin\java -classpath .;d:\jd\jpda.jar
tty.TTY -attach javadebug
Internal exception: java.lang.NullPointerException
at tty.VMConnection.open(VMConnection.java:138)
at tty.Env.init(Env.java:68)
at tty.TTY.main(TTY.java:923)
The code in VMConnection looks like this:
132 synchronized VirtualMachine open() {
133 if (connector instanceof LaunchingConnector) {
134 vm = launchTarget();
135 } else if (connector instanceof AttachingConnector) {
136 vm = attachTarget();
137 // Allow debugger operations like 'cont'
138 ThreadInfo.setCurrentThread(ThreadInfo.getThread(1).thread);
. . .
It works when I try to attach using the "jdb" executable provided with jpda1_0-
win.zip:
C:\jpda\bin>jdb -attach javadebug
Initializing jdb...
Signal dispatcher[1] threads
Group system:
1. (java.lang.Thread)0x3 Signal dispatcher running
2. (java.lang.ref.Reference$ReferenceHandler)0x4 Reference Handler cond. waitin
3. (java.lang.ref.Finalizer$FinalizerThread)0x5 Finalizer cond. waitin
Group main:
4. (java.awt.EventDispatchThread)0x7 AWT-EventQueue-0 cond. waiting
5. (sun.awt.PostEventQueue)0x8 PostEventQueue-0 cond. waiting
6. (java.lang.Thread)0x9 AWT-Windows running
7. (ProcessRunWindow$1)0xa input stream running
8. (ProcessRunWindow$2)0xb error stream running
9. (java.lang.Thread)0xc Thread-0 cond. waiting
Signal dispatcher[1]
Source for test class:
import java.awt.*;
/*
* Simple generated by BuildWin
* Generated from the file D:\jd\work\Simple.bwn
* Fri Apr 14 12:16:41 EDT 2000
*/
/**
*
*/
class Simple extends Frame {
boolean exitOnClose=false;
Label label1=new Label(); //
/**
* Test driver for the class Simple
*/
public static void main(String[] args) {
Simple tSimple = new Simple();
tSimple.exitOnClose=true;
tSimple.pack();
// you can tSimple.setSize(width,height); here
// you can tSimple.setLocation(x,y); here
tSimple.show();
}
/**
* Handles only the window close event
*/
public boolean handleEvent(Event event) {
if (event.id == Event.WINDOW_DESTROY && exitOnClose) System.exit(0);
if (event.id == Event.WINDOW_DESTROY) dispose();
return super.handleEvent(event);
}
/**
* Constructor of a Simple GUI.
*/
Simple() {
setTitle("Simple");
setForeground(Color.black);
setBackground(Color.white);
setFont(new Font("Courier",0,12));
GridBagConstraints c = new GridBagConstraints();
BorderLayout borderlayout=new BorderLayout();
setLayout(borderlayout);
label1.setText("Waiting for a close event");
add(label1);
MenuBar mb = new MenuBar();
setMenuBar(mb);
}
}
(Review ID: 105650)
======================================================================
Name: tb29552 Date: 09/22/2000
java version "1.3.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0-C)
Java HotSpot(TM) Client VM (build 1.3.0-C, mixed mode)
The jdb delivered with Java 2 SDK, Standard Edition, v1.3 will fail
with a NullPointerException if you attempt to attach to a running VM
and the original (main) thread is no longer running. This problem
occurs when trying to attach to an Apache Jakarta-Tomcat server
because the initial thread runs for only a short time -- just long
enough to startup another thread.
Below is a short program (TestThreads.java) to demonstrate the problem.
It has a main thread that runs for a short time. The main thread
creates a new thread that continues to run for 30 seconds after the
main thread completes. To reproduce the problem:
1. Save the sample code to a file named TestThreads.java.
2. Compile for debugging.
javac -g TestThreads.java
3. Execute the test program, starting the VM with the
appropriate options.
java -Xdebug -
Xrunjdwp:transport=dt_shmem,address=jdbdebug,server=y,suspend=n TestThreads
4. In another window on the same system, attempt to connect to the
running VM. You have to connect after the main thread exits
(which happens pretty much instantly) and before the new thread
exits (which takes about 30 seconds).
jdb -attach jdbdebug
5. Note that jdb fails with the following stack trace:
Internal exception: java.lang.NullPointerException
at com.sun.tools.example.debug.tty.VMConnection.open
(VMConnection.java:138)
at com.sun.tools.example.debug.tty.Env.init(Env.java:68)
at com.sun.tools.example.debug.tty.TTY.main(TTY.java:923)
The reason appears to be that the jdb startup code wants to set the
thread whose id=1 (main) to be the current thread. The value of 1 is
hardcoded. See "Orig VMConnection.open() method" and
"ThreadInfo.getThread() method" below. However, in this instance, no
thread with id=1 exists and getThread() returns null. The
VMConnection.open() method does not check for a null return value from
ThreadInfo.getThread().
I fixed the problem by changing the startup code to simply set the
thread with the lowest id to be the current thread. I assume that
it's not really important which thread is initially designated as the
current thread as long as the debugger gets control to give the user
the opportunity to interact with the debugger. Please let me know if
this is not correct.
The fix is shown in "Modified VMConnection.open() method" and "New
ThreadInfo.setDefaultThread() method" below. These are from
com.sun.tools.example.debug.tty.VMConnection.java and
com.sun.tools.example.debug.tty.ThreadInfo.java in
demo/jpda/examples.jar respectively. The resulting class files
(ThreadInfo.class, VMConnection.class, and VMConnection$1.class)
replace the ones in tools.jar.
Let me know if you need more info.
===== TestThreads.java =====
public class TestThreads {
public TestThreads() {
System.err.println("Creating new thread");
MyThread myThread = new MyThread();
System.err.println("New thread created");
myThread.start();
return;
}
public static void main(String args[] ) {
System.err.println("Main thread running");
TestThreads t = new TestThreads();
System.err.println("Main thread exiting");
return;
} // end method main
class MyThread extends Thread {
public void run() {
int cnt = 0;
System.err.println("\tNew thread running");
try {
for (int i = 0; i < 15; ++i) {
Thread.sleep(2000);
System.err.println("\tNew thread working");
}
} catch (InterruptedException e) {
System.err.println("\tInterruptedException");
}
System.err.println("\tNew thread exiting");
return;
}
public void start() {
System.err.println("\tStarting new thread");
super.start();
System.err.println("\tNew thread started");
}
}
} // end class TestThreads
===== end TestThreads.java =====
===== Orig VMConnection.open() method ====
synchronized VirtualMachine open() {
if (connector instanceof LaunchingConnector) {
vm = launchTarget();
} else if (connector instanceof AttachingConnector) {
vm = attachTarget();
// Allow debugger operations like 'cont'
ThreadInfo.setCurrentThread(ThreadInfo.getThread(1).thread);
} else if (connector instanceof ListeningConnector) {
vm = listenTarget();
// Allow debugger operations like 'cont'
ThreadInfo.setCurrentThread(ThreadInfo.getThread(1).thread);
} else {
throw new InternalError("Invalid connect type");
}
vm.setDebugTraceMode(traceFlags);
setEventRequests(vm);
resolveEventRequests();
// Env.out.println("Connected to " + target);
return vm;
}
===== end Orig VMConnection.open() method ====
===== Modified VMConnection.open() method =====
synchronized VirtualMachine open() {
if (connector instanceof LaunchingConnector) {
vm = launchTarget();
} else {
if (connector instanceof AttachingConnector) {
vm = attachTarget();
} else if (connector instanceof ListeningConnector) {
vm = listenTarget();
} else {
throw new InternalError("Invalid connect type");
}
// Allow debugger operations like 'cont'
ThreadInfo.setDefaultThread();
}
vm.setDebugTraceMode(traceFlags);
setEventRequests(vm);
resolveEventRequests();
// Env.out.println("Connected to " + target);
return vm;
}
===== end Modified VMConnection.open() method =====
===== ThreadInfo.getThread() method =====
static ThreadInfo getThread(long id) {
ThreadInfo retInfo = null;
synchronized (threads) {
Iterator iter = threads().iterator();
while (iter.hasNext()) {
ThreadInfo ti = (ThreadInfo)iter.next();
if (ti.thread.uniqueID() == id) {
retInfo = ti;
break;
}
}
}
return retInfo;
}
===== end ThreadInfo.getThread() method =====
===== New ThreadInfo.setDefaultThread() method =====
static void setDefaultThread() {
long threadId = -1;
ThreadInfo threadInfo = null;
synchronized (threads) {
Iterator iter = threads().iterator();
while (iter.hasNext()) {
ThreadInfo ti = (ThreadInfo)iter.next();
if ((-1 == threadId) || (ti.thread.uniqueID() < threadId)) {
threadId = ti.thread.uniqueID();
threadInfo = ti;
}
}
}
// No need to throw exception here. A VMNotConnectedException will
// be thrown later when we actually try to use currentThread.
// cmb 21-Sep-2000
if (null != threadInfo) {
ThreadInfo.setCurrentThread(threadInfo.thread);
}
return;
}
===== end New ThreadInfo.setDefaultThread() method =====
(Review ID: 109895)
======================================================================
- backported by
-
JDK-2034568 JPDA example to attach to a running VM hits NullPointerException
-
- Resolved
-