JDK-8134759 : jdb: Incorrect stepping inside finally block
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 8
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2015-08-31
  • Updated: 2016-04-27
  • Resolved: 2015-10-27
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 Availability Release.

To download the current JDK release, click here.
JDK 8 JDK 9
8u101Fixed 9 b89Fixed
Description
$ jdb Main
Initializing jdb ...
> stop at Main:9
Deferring breakpoint Main:9.
It will be set after the class is loaded.
> run
run Main
Set uncaught java.lang.Throwable
Set deferred uncaught java.lang.Throwable
>
VM Started: Set deferred breakpoint Main:9

Breakpoint hit: "thread=main", Main.test(), line=9 bci=2
9          if (args.length < - 1) {  // Any non-trivial condition evaluating to `false` would do

main[1] step
>
Step completed: "thread=main", Main.test(), line=10 bci=16
10            System.out.println("not null");

Source:
public class Main {
  public static void main(String[] args) {
    test(args);
  }
  public static Void test(String[] args) {
    try {
      return null;
    } finally {
      if (args.length < - 1) {  // Any non-trivial condition evaluating to `false` would do
        System.out.println("not null");
      }
    }
  }
}
Comments
After re-compiling the java class file with the above change the stepping displays the expected output: > stop at Main:9 Deferring breakpoint Main:9. It will be set after the class is loaded. > run run Main [...] Breakpoint hit: "thread=main", Main.test(), line=9 bci=2 9 if (args.length < - 1) { // Any non-trivial condition evaluating to 'false' would do main[1] step > Step completed: "thread=main", Main.test(), line=7 bci=16 7 return null;
20-10-2015

Problem is that linenumbers are not generated correctly by javac. Suggested fix: diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java @@ -1697,6 +1697,11 @@ public void visitReturn(JCReturn tree) { int limit = code.nextreg; final Env<GenContext> targetEnv; + + /* Save and then restore the location of the return in case a finally + * is expanded (with unwind()) in the middle of our bytecodes. + */ + int tmpPos = code.pendingStatPos; if (tree.expr != null) { Item r = genExpr(tree.expr, pt).load(); if (hasFinally(env.enclMethod, env)) { @@ -1704,17 +1709,10 @@ r.store(); } targetEnv = unwind(env.enclMethod, env); + code.pendingStatPos = tmpPos; r.load(); code.emitop0(ireturn + Code.truncate(Code.typecode(pt))); } else { - /* If we have a statement like: - * - * return; - * - * we need to store the code.pendingStatPos value before generating - * the finalizer. - */ - int tmpPos = code.pendingStatPos; targetEnv = unwind(env.enclMethod, env); code.pendingStatPos = tmpPos; code.emitop0(return_);
14-10-2015