Debugging Using JDB

While testing your program, you may encounter errors ("bugs") in one of two ways:
  1. the program may crash (throw an exception), or
  2. it may produce incorrect output.
In either case, you can use the debugger jdb to help track down the error.

To learn about using jdb, print and read the JDB Quick Reference Guide. Then try the two exercises below.

Example 1: Using jdb after a crash

  1. Create a new directory and copy into it the files from ~vernon/public/html/cs367/tutorials/jdb. To do this, change to your new directory and type: Note that there is a dot "." at the end of the above command. The file Person.java defines a very simple Person class, with a constructor that initializes the person to be 10 years old, and an age method that returns the person's current age. The program in Bug.java includes the declaration of a Person array. It uses a loop to verify that everyone in the array has been initialized to be 10 years old.

  2. Before you can compile and run Java programs, you need to set up your environment so that the compiler can find the standard Java classes. To do this, change to your top-level directory by typing Now edit your .cshrc.local file by typing (be sure to include the dot as the first character of the file name). Type: followed by a newline (i.e., press the Enter key). Note that the character following jdk above is a "one" and not the letter "l". Write out the modified file by typing and exit from emacs by typing (Don't type the word "control-x", just hold down the ctrl key while typing an x.) Now type Then go back to the directory you created in step 1.

  3. Compile your Java files by typing

  4. Run the Bug program (type: java Bug). This should cause a null pointer exception to be thrown. If the error message does not tell you where the exception occurred, run the program again as follows: java -Djava.compiler=NONE Bug This time you should see that the exception is thrown on line 10.

  5. Use jdb to find the problem. First type: jdb Bug. When jdb is ready (it gives you a ">" prompt), tell it to stop at the beginning of the program by typing: stop in Bug.main, then start the program by typing: run Bug

  6. You should get a message saying that your breakpoint was hit.

  7. Now you can set another breakpoint at the statement that caused the null pointer exception by typing: stop at Bug:10 (Note that when you set a breakpoint at a method, you must use stop in and a dot, while when you set a breakpoint at a line number you must use stop at and a colon.) Now let the program continue running until it gets to line 10, by typing: cont

  8. The program will stop the first time it gets to line 10. Type list to see line 10 and the surrounding lines. You should see that line 10 is: if (family[j].age() != 10) {. A null pointer exception means that there was an attempt to access a field or method of an Object whose value is null. On line 10, the age method of family[j] is being called. Is it possible that family[j] is null? To see whether this is indeed the case, type: print j (jdb should print j = 0), then type print family[0]. You should find that indeed family[0] is null, so it is wrong to try to call its age method.

  9. Look at the previous code that set the value of family. Do you understand why family[0] (and all of the other elements of the array) are null?

Example 2: Using jdb to understand bad output

  1. Exit from jdb by typing: quit. Fix the problem you discovered in Example 1 by editing Bug.java.

  2. Recompile Bug.java (type: jikes -g Bug.java).

  3. Run Bug again. It should not crash, but you should get lots of messages saying that the people in the array are not 10 years old. It seems that either the Person constructor method or its age method is not working. We can find out whether the Person constructor is working by printing the value of a Person's myAge field after the constructor has been called.

  4. Run jdb again (type: jdb Bug), and set a breakpoint at the beginning of the program (stop in Bug.main). Then start the program (run Bug).

  5. Use the list command to look at the code to see where to set the next breakpoint. Find the line number where you call the Person constructor, and set a breakpoint there, then continue execution.

  6. Use the next command to execute the current line (the call to the Person constructor).

  7. Use the print command to look at the value of the Person's "myAge" field (print family[0].myAge).

  8. You should see that the value is 0, instead of 10 as expected.

  9. Look at the code for the Person constructor (unfortunately, there doesn't seem to be a way to do this in jdb unless you are currently stopped at a breakpoint that is in a Person method, so you'll have to use a text editor in another window to look at the code). Can you find and fix the problem?