Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4349534

regression - bad LocalVariableTable attribute when no initialization needed

    XMLWordPrintable

Details

    • Bug
    • Resolution: Fixed
    • P4
    • 1.4.2
    • cdc-hi_1.0, cdc_1.0.1, 1.3.0
    • tools
    • mantis
    • generic, x86
    • generic, solaris_7, windows_2000

    Description

      Bug was (see original bug report which follows):
      JPDA: LocalVariable.isVisible() returns wrong value when local var uninitialized

      Cause of problem determined to be that new javac compiler generates
      incorrect LocalVariableTable attributes for variables which do not
      need to be initialized. Specifically, the generated table includes
      pc values where the variable does not have value.

      The example below shows first the result of compiling with the old
      compiler then the new. After this is the original report.

      % cat -n Test.java
           1 class Test
           2 {
           3 public static void main(String[] args)
           4 {
           5 int i = 1;
           6 String command;
           7 if (i == 0) {
           8 command = "0";
           9 } else if (i == 1) {
          10 command = "1";
          11 } else {
          12 command = null;
          13 }
          14 }
          15 }
      % /usr/local/java/jdk1.2.2-solaris/bin/javac -g Test.java
      % javap -l -c Test
      Compiled from Test.java
      class Test extends java.lang.Object {
          Test();
          public static void main(java.lang.String []);

      Method Test()
         0 aload_0
         1 invokenonvirtual #5 <Method java.lang.Object.<init>()V>
         4 return

      Method void main(java.lang.String [])
         0 iconst_1
         1 istore_1
         2 iload_1
         3 ifne 12
         6 ldc #1 <String "0">
         8 astore_2
         9 goto 25
        12 iload_1
        13 iconst_1
        14 if_icmpne 23
        17 ldc #2 <String "1">
        19 astore_2
        20 goto 25
        23 aconst_null
        24 astore_2
        25 return


      Line numbers for method Test()
         line 1: 0

      Line numbers for method void main(java.lang.String [])
         line 5: 0
         line 7: 2
         line 8: 6
         line 7: 9
         line 9: 12
         line 10: 17
         line 9: 20
         line 12: 23
         line 3: 25


      Local variables for method Test()
         Test this pc=0, length=5, slot=0

      Local variables for method void main(java.lang.String [])
         java.lang.String args[] pc=0, length=26, slot=0
         int i pc=2, length=24, slot=1
         java.lang.String command pc=9, length=3, slot=2
         java.lang.String command pc=20, length=3, slot=2
         java.lang.String command pc=25, length=1, slot=2

      }

      Note that the local variable table above correctly separates
      the three areas where the variable is valid. Now from 1.3 --

      % /usr/local/java/jdk1.3.0-solaris/solaris/bin/javac -g Test.java
      % javap -l -c Test
      Compiled from Test.java
      class Test extends java.lang.Object {
          Test();
          public static void main(java.lang.String []);

      Method Test()
         0 aload_0
         1 invokenonvirtual #1 <Method java.lang.Object.<init>()V>
         4 return

      Method void main(java.lang.String [])
         0 iconst_1
         1 istore_1
         2 iload_1
         3 ifne 12
         6 ldc #2 <String "0">
         8 astore_2
         9 goto 25
        12 iload_1
        13 iconst_1
        14 if_icmpne 23
        17 ldc #3 <String "1">
        19 astore_2
        20 goto 25
        23 aconst_null
        24 astore_2
        25 return


      Line numbers for method Test()
         line 1: 0

      Line numbers for method void main(java.lang.String [])
         line 5: 0
         line 7: 2
         line 8: 6
         line 9: 12
         line 10: 17
         line 12: 23
         line 14: 25


      Local variables for method Test()
         Test this pc=0, length=5, slot=0

      Local variables for method void main(java.lang.String [])
         java.lang.String args[] pc=0, length=26, slot=0
         int i pc=2, length=23, slot=1
         java.lang.String command pc=9, length=16, slot=2

      }

      Here the area where it is supposed to have value spans areas
      where it does not. See below to see what effect this has.

      ------ original report ----------
      Name: rl16235 Date: 06/29/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)

      StackFrame.getValue() consistently throws a
      com.sun.jdi.InconsistentDebugInfoException when getValue() is requested on a
      LocalVariable that is currently uninitialized. Example code:

      class Test
      {
          public static void main(String[] args)
          {
              int i = 1;
              String command;
              if (i == 0) { // A: set initial breakpoint here and then step
                  command = "0";
              } else if (i == 1) { B: // when here, exception is thrown
                  command = "1";
              } else {
                  command = null;
              }
          }
      }

      The example above compiles because the compiler has determined that the local
      variable 'command' will always be initialized after executing the if-elseif-
      else statements thus 'command' does not have to be explicitly assigned an
      initial value unlike local variable 'i'. When we query the value for the yet
      uninitialized local variable 'command' in our debugger, a
      com.sun.jdi.InconsistentDebugInfoException gets thrown. The LocalVariable
      object representing 'command' returns true when isVisible() at point B: which
      is problem where the problem lies.

      ###@###.### 2000-06-29
      Here are steps to reproduce with jdb.
      sunni-104% java -version
      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, interpreted mode)

      sunni-105% jdb -tclassic Test
      Initializing jdb...
      > stop at Test:7
      Deferring breakpoint Test:7.
      It will be set after the class is loaded.
      > run
      run Test

      VM Started: > Set deferred breakpoint Test:7

      Breakpoint hit: thread="main", Test.main(), line=7, bci=2
        7 if (i == 0) { // A: set initial breakpoint here and then step

      main[1] step

      Step completed: thread="main", Test.main(), line=9, bci=12
        9 } else if (i == 1) { B: // when here, exception is thrown

      main[1] step

      Step completed: main[1] thread="main", Test.main(), line=10, bci=17
        10 command = "1";

      main[1] dump command
      com.sun.jdi.InconsistentDebugInfoException
              at com.sun.tools.jdi.JDWPException.toJDIException(JDWPException.java:46)
              at com.sun.tools.jdi.StackFrameImpl.getValues(StackFrameImpl.java:230)
              at com.sun.tools.jdi.StackFrameImpl.getValue(StackFrameImpl.java:188)
              at com.sun.tools.example.debug.expr.LValue$LValueLocal.getValue(LValue.java:233)
              at com.sun.tools.example.debug.expr.ExpressionParser.evaluate(ExpressionParser.java:54)
              at com.sun.tools.example.debug.tty.Commands.evaluate(Commands.java:72)
              at com.sun.tools.example.debug.tty.Commands.doPrint(Commands.java:1362)
              at com.sun.tools.example.debug.tty.Commands$3.run(Commands.java:1395)


      (Review ID: 106669)
      ======================================================================

      Attachments

        Issue Links

          Activity

            People

              gafter Neal Gafter
              rlingaiaorcl Ranjit Lingaiah (Inactive)
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:
                Imported:
                Indexed: