changeset 14685:bed2bf575d93

8152893: StackWalker#getCallerClass is not filtering hidden/ reflection frames when walker is configured to show hidden /reflection frames Reviewed-by: mchung
author bchristi
date Fri, 03 Jun 2016 17:01:23 -0700
parents d50d02361da6
children 5be0d816aff5
files src/java.base/share/classes/java/lang/StackStreamFactory.java src/java.base/share/classes/java/lang/StackWalker.java test/java/lang/StackWalker/GetCallerClassTest.java
diffstat 3 files changed, 41 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/java/lang/StackStreamFactory.java	Fri Jun 03 16:31:13 2016 -0700
+++ b/src/java.base/share/classes/java/lang/StackStreamFactory.java	Fri Jun 03 17:01:23 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -680,7 +680,8 @@
             // 1: caller-sensitive method
             // 2: caller class
             while (n < 2 && (caller = nextFrame()) != null) {
-                if (isMethodHandleFrame(caller)) continue;
+                if (isMethodHandleFrame(caller)) { continue; }
+                if (isReflectionFrame(caller)) { continue; }
                 frames[n++] = caller;
             }
             if (frames[1] == null) {
--- a/src/java.base/share/classes/java/lang/StackWalker.java	Fri Jun 03 16:31:13 2016 -0700
+++ b/src/java.base/share/classes/java/lang/StackWalker.java	Fri Jun 03 17:01:23 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -468,23 +468,23 @@
      * Gets the {@code Class} object of the caller invoking the method
      * that calls this {@code getCallerClass} method.
      *
-     * <p> Reflection frames, {@link java.lang.invoke.MethodHandle} and
+     * <p> Reflection frames, {@link java.lang.invoke.MethodHandle}, and
      * hidden frames are filtered regardless of the
      * {@link Option#SHOW_REFLECT_FRAMES SHOW_REFLECT_FRAMES}
      * and {@link Option#SHOW_HIDDEN_FRAMES SHOW_HIDDEN_FRAMES} options
-     * this {@code StackWalker} has been configured.
+     * this {@code StackWalker} has been configured with.
      *
      * <p> This method throws {@code UnsupportedOperationException}
-     * if this {@code StackWalker} is not configured with
-     * {@link Option#RETAIN_CLASS_REFERENCE RETAIN_CLASS_REFERENCE} option,
+     * if this {@code StackWalker} is not configured with the
+     * {@link Option#RETAIN_CLASS_REFERENCE RETAIN_CLASS_REFERENCE} option.
      * This method should be called when a caller frame is present.  If
-     * it is called from the last frame on the stack;
+     * it is called from the last frame on the stack,
      * {@code IllegalStateException} will be thrown.
      *
      * @apiNote
      * For example, {@code Util::getResourceBundle} loads a resource bundle
      * on behalf of the caller.  It calls this {@code getCallerClass} method
-     * to find the method calling {@code Util::getResourceBundle} and use the caller's
+     * to find the method calling {@code Util::getResourceBundle} and uses the caller's
      * class loader to load the resource bundle. The caller class in this example
      * is the {@code MyTool} class.
      *
@@ -519,7 +519,7 @@
      * When the {@code getCallerClass} method is called from a method that
      * is the last frame on the stack,
      * for example, {@code static public void main} method launched by the
-     * {@code java} launcher or a method invoked from a JNI attached thread.
+     * {@code java} launcher, or a method invoked from a JNI attached thread,
      * {@code IllegalStateException} is thrown.
      *
      * @return {@code Class} object of the caller's caller invoking this method.
--- a/test/java/lang/StackWalker/GetCallerClassTest.java	Fri Jun 03 16:31:13 2016 -0700
+++ b/test/java/lang/StackWalker/GetCallerClassTest.java	Fri Jun 03 17:01:23 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8140450
+ * @bug 8140450 8152893
  * @summary Basic test for StackWalker.getCallerClass()
  * @run main/othervm GetCallerClassTest
  * @run main/othervm GetCallerClassTest sm
@@ -41,6 +41,7 @@
 import java.security.Policy;
 import java.security.ProtectionDomain;
 import java.util.Arrays;
+import java.util.EnumSet;
 import java.util.List;
 
 public class GetCallerClassTest {
@@ -65,16 +66,20 @@
         }
         new GetCallerClassTest(StackWalker.getInstance(), true).test();
         new GetCallerClassTest(StackWalker.getInstance(RETAIN_CLASS_REFERENCE), false).test();
+        new GetCallerClassTest(StackWalker.getInstance(EnumSet.of(RETAIN_CLASS_REFERENCE,
+                                                                  SHOW_HIDDEN_FRAMES)), false).test();
     }
 
     public void test() {
         new TopLevelCaller().run();
+        new LambdaTest().run();
         new Nested().createNestedCaller().run();
         new InnerClassCaller().run();
         new ReflectionTest().run();
 
         List<Thread> threads = Arrays.asList(
                 new Thread(new TopLevelCaller()),
+                new Thread(new LambdaTest()),
                 new Thread(new Nested().createNestedCaller()),
                 new Thread(new InnerClassCaller()),
                 new Thread(new ReflectionTest())
@@ -149,7 +154,7 @@
 
     public static void assertEquals(Class<?> c, Class<?> expected) {
         if (expected != c) {
-            throw new RuntimeException(c + " != " + expected);
+            throw new RuntimeException("Got " + c + ", but expected " + expected);
         }
     }
 
@@ -172,6 +177,28 @@
         }
     }
 
+    class LambdaTest implements Runnable {
+        public void run() {
+            Runnable lambdaRunnable = () -> {
+                try {
+                    Class<?> c = walker.getCallerClass();
+
+                    assertEquals(c, LambdaTest.class);
+                    if (expectUOE) { // Should have thrown
+                        throw new RuntimeException("Didn't get expected exception");
+                    }
+                } catch (Throwable e) {
+                    if (expectUOE && causeIsUOE(e)) {
+                        return; /* expected */
+                    }
+                    System.err.println("Unexpected exception:");
+                    throw new RuntimeException(e);
+                }
+            };
+            lambdaRunnable.run();
+        }
+    }
+
     class Nested {
         NestedClassCaller createNestedCaller() { return new NestedClassCaller(); }
         class NestedClassCaller implements Runnable {