1/*
2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24package jdk.test;
25
26import java.lang.invoke.MethodHandle;
27import java.lang.invoke.MethodHandles;
28import java.lang.invoke.MethodHandles.Lookup;
29import java.lang.invoke.MethodType;
30import java.lang.reflect.Method;
31import java.security.Permission;
32import java.security.PermissionCollection;
33import java.security.Permissions;
34import java.security.Policy;
35import java.security.ProtectionDomain;
36import java.util.CSM.Result;
37import java.util.function.Supplier;
38
39/**
40 * This test invokes StackWalker::getCallerClass via static reference,
41 * reflection, MethodHandle, lambda.  Also verify that
42 * StackWalker::getCallerClass can't be called from @CallerSensitive method.
43 */
44public class CallerSensitiveTest {
45    private static final String NON_CSM_CALLER_METHOD = "getCallerClass";
46    private static final String CSM_CALLER_METHOD = "caller";
47
48    public static void main(String... args) throws Throwable {
49        boolean sm = false;
50        if (args.length > 0 && args[0].equals("sm")) {
51            sm = true;
52            PermissionCollection perms = new Permissions();
53            perms.add(new RuntimePermission("getStackWalkerWithClassReference"));
54            Policy.setPolicy(new Policy() {
55                @Override
56                public boolean implies(ProtectionDomain domain, Permission p) {
57                    return perms.implies(p);
58                }
59            });
60            System.setSecurityManager(new SecurityManager());
61        }
62
63        System.err.format("Test %s security manager.%n",
64                          sm ? "with" : "without");
65
66        CallerSensitiveTest cstest = new CallerSensitiveTest();
67        // test static call to java.util.CSM::caller and CSM::getCallerClass
68        cstest.staticMethodCall();
69        // test java.lang.reflect.Method call
70        cstest.reflectMethodCall();
71        // test java.lang.invoke.MethodHandle
72        cstest.invokeMethodHandle(Lookup1.lookup);
73        cstest.invokeMethodHandle(Lookup2.lookup);
74        // test method ref
75        cstest.lambda();
76
77        LambdaTest.lambda();
78
79        if (failed > 0) {
80            throw new RuntimeException(failed + " test cases failed.");
81        }
82    }
83
84    void staticMethodCall() {
85        java.util.CSM.caller();
86
87        Result result = java.util.CSM.getCallerClass();
88        checkNonCSMCaller(CallerSensitiveTest.class, result);
89    }
90
91    void reflectMethodCall() throws Throwable {
92        Method method1 = java.util.CSM.class.getMethod(CSM_CALLER_METHOD);
93        method1.invoke(null);
94
95        Method method2 = java.util.CSM.class.getMethod(NON_CSM_CALLER_METHOD);
96        Result result = (Result) method2.invoke(null);
97        checkNonCSMCaller(CallerSensitiveTest.class, result);
98    }
99
100    void invokeMethodHandle(Lookup lookup) throws Throwable {
101        MethodHandle mh1 = lookup.findStatic(java.util.CSM.class, CSM_CALLER_METHOD,
102            MethodType.methodType(Class.class));
103        Class<?> c = (Class<?>)mh1.invokeExact();
104
105        MethodHandle mh2 = lookup.findStatic(java.util.CSM.class, NON_CSM_CALLER_METHOD,
106            MethodType.methodType(Result.class));
107        Result result = (Result)mh2.invokeExact();
108        checkNonCSMCaller(CallerSensitiveTest.class, result);
109    }
110
111    void lambda() {
112        Result result = LambdaTest.getCallerClass.get();
113        checkNonCSMCaller(CallerSensitiveTest.class, result);
114
115        LambdaTest.caller.get();
116    }
117
118    static int failed = 0;
119
120    static void checkNonCSMCaller(Class<?> expected, Result result) {
121        if (result.callers.size() != 1) {
122            throw new RuntimeException("Expected result.callers contain one element");
123        }
124        if (expected != result.callers.get(0)) {
125            System.err.format("ERROR: Expected %s but got %s%n", expected,
126                result.callers);
127            result.frames.stream()
128                .forEach(f -> System.err.println("   " + f));
129            failed++;
130        }
131    }
132
133    static class Lookup1 {
134        static Lookup lookup = MethodHandles.lookup();
135    }
136
137    static class Lookup2 {
138        static Lookup lookup = MethodHandles.lookup();
139    }
140
141    static class LambdaTest {
142        static Supplier<Class<?>> caller = java.util.CSM::caller;
143        static Supplier<Result> getCallerClass = java.util.CSM::getCallerClass;
144
145        static void caller() {
146            caller.get();
147        }
148        static Result getCallerClass() {
149            return getCallerClass.get();
150        }
151
152        static void lambda() {
153            Result result = LambdaTest.getCallerClass();
154            checkNonCSMCaller(LambdaTest.class, result);
155
156            LambdaTest.caller();
157        }
158    }
159}
160