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

java.lang.SecurityManager.getClassContext() does not return an array the same length as the of methods on the execution stack with lambdas

    XMLWordPrintable

Details

    Description

      FULL PRODUCT VERSION :
      Happens on all Java version 8u60 and later; I'm currently using:
      openjdk version "1.8.0_91"
      OpenJDK Runtime Environment (build 1.8.0_91-b14)
      OpenJDK 64-Bit Server VM (build 25.91-b14, mixed mode)

      ADDITIONAL OS VERSION INFORMATION :
      Happens on all OS's, here's the one I'm currently using:
      Linux candrews-l1 4.5.5-300.fc24.x86_64 #1 SMP Thu May 19 13:05:32 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux

      A DESCRIPTION OF THE PROBLEM :
      The javadoc for java.lang.SecurityManager.getClassContext() states:
      "The length of the array is the number of methods on the execution stack. The element at index 0 is the class of the currently executing method, the element at index 1 is the class of that method's caller, and so on." - https://docs.oracle.com/javase/8/docs/api/java/lang/SecurityManager.html#getClassContext--

      However, java.lang.Throwable.getStackTrace() filters out generated lambda classes as of Java 8u60, see http://bugs.java.com/view_bug.do?bug_id=8025636 Since java.lang.SecurityManager.getClassContext() does not filter out generated lambda classes, the javadoc statement that getClassContext() matches the call stack does not hold true.

      REGRESSION. Last worked in version 8u73

      ADDITIONAL REGRESSION INFORMATION:
      java.lang.SecurityManager.getClassContext() aligns with java.lang.Throwable.getStackTrace() when called within a lambda in any Java version before 8u60 as documented at http://bugs.java.com/view_bug.do?bug_id=8025636

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Run the test case I've provided in the answer to the "Source code for an executable test case" question.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The test case should output:
      ==========Testing without lambdas==========
      Bug is NOT present
      ==========Testing with lambdas==========
      Bug is NOT present
      ACTUAL -
      The test case actually outputs (on Java 8u60 and later):
      ==========Testing without lambdas==========
      Bug is NOT present
      ==========Testing with lambdas==========
      BUG IS PRESENT
      Stacktrace length: 4
      Class Context length: 6
      Stacktrace:
      Test.testStackTraceLengthMatchesClassContextLength(Test.java:24)
      Test.lambda$0(Test.java:19)
      java.lang.Thread.run(Thread.java:745)
      Test.main(Test.java:20)
      Class Context:
      class Test$ClassContextSecurityManager
      class Test
      class Test
      class Test$$Lambda$1/791452441
      class java.lang.Thread
      class Test


      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      import java.util.Arrays;

      public class Test {

      private static class ClassContextSecurityManager extends SecurityManager {
      @Override
      public Class[] getClassContext() {
      return super.getClassContext();
      }
      }

      public static void main(String[] args) {
      // first, show the bug is not present when there aren't lambdas in the
      // call stack
      System.out.println("==========Testing without lambdas==========");
      testStackTraceLengthMatchesClassContextLength();
      new Thread(() -> {
      System.out.println("==========Testing with lambdas==========");
      testStackTraceLengthMatchesClassContextLength();
      }).run();
      }

      private static void testStackTraceLengthMatchesClassContextLength() {
      StackTraceElement[] stackTrace = new Throwable().getStackTrace();
      Class[] classContext = new ClassContextSecurityManager().getClassContext();
      // class context will always include ClassContextSecurityManager,
      // which is not in the stack trace, so the length of the class
      // context array should always be 1 more than the stack trace length
      if (stackTrace.length == classContext.length - 1) {
      System.out.println("Bug is NOT present");
      } else {
      System.out.println("BUG IS PRESENT");
      System.out.println("Stacktrace length: " + stackTrace.length);
      System.out.println("Class Context length: " + classContext.length);
      System.out.println("Stacktrace:");
      Arrays.stream(stackTrace).forEach(System.out::println);
      System.out.println("Class Context:");
      Arrays.stream(classContext).forEach(System.out::println);
      }
      }

      }

      ---------- END SOURCE ----------

      Attachments

        Issue Links

          Activity

            People

              mullan Sean Mullan
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: