Skip to content

Commit b7e143e

Browse files
author
Joel Borggrén-Franck
committed
8073056: Repeating annotations throws java.security.AccessControlException with a SecurityManager
Reviewed-by: ahgross, darcy
1 parent eaa4299 commit b7e143e

File tree

7 files changed

+264
-14
lines changed

7 files changed

+264
-14
lines changed

jdk/src/java.base/share/classes/java/lang/reflect/Method.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,21 @@ Method copy() {
160160
return res;
161161
}
162162

163+
/**
164+
* Make a copy of a leaf method.
165+
*/
166+
Method leafCopy() {
167+
if (this.root == null)
168+
throw new IllegalArgumentException("Can only leafCopy a non-root Method");
169+
170+
Method res = new Method(clazz, name, parameterTypes, returnType,
171+
exceptionTypes, modifiers, slot, signature,
172+
annotations, parameterAnnotations, annotationDefault);
173+
res.root = root;
174+
res.methodAccessor = methodAccessor;
175+
return res;
176+
}
177+
163178
/**
164179
* Used by Excecutable for annotation sharing.
165180
*/

jdk/src/java.base/share/classes/java/lang/reflect/ReflectAccess.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,9 @@ public byte[] getExecutableTypeAnnotationBytes(Executable ex) {
139139
public Method copyMethod(Method arg) {
140140
return arg.copy();
141141
}
142+
public Method leafCopyMethod(Method arg) {
143+
return arg.leafCopy();
144+
}
142145

143146
public Field copyField(Field arg) {
144147
return arg.copy();

jdk/src/java.base/share/classes/sun/reflect/LangReflectAccess.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,9 @@ public void setConstructorAccessor(Constructor<?> c,
104104
/** Makes a "child" copy of a Method */
105105
public Method copyMethod(Method arg);
106106

107+
/** Makes a copy of this non-root a Method */
108+
public Method leafCopyMethod(Method arg);
109+
107110
/** Makes a "child" copy of a Field */
108111
public Field copyField(Field arg);
109112

jdk/src/java.base/share/classes/sun/reflect/ReflectionFactory.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,14 @@ public Method copyMethod(Method arg) {
302302
return langReflectAccess().copyMethod(arg);
303303
}
304304

305+
/** Makes a copy of the passed method. The returned method is NOT
306+
* a "child" but a "sibling" of the Method in arg. Should only be
307+
* used on non-root methods. */
308+
public Method leafCopyMethod(Method arg) {
309+
return langReflectAccess().leafCopyMethod(arg);
310+
}
311+
312+
305313
/** Makes a copy of the passed field. The returned field is a
306314
"child" of the passed one; see the comments in Field.java for
307315
details. */

jdk/src/java.base/share/classes/sun/reflect/annotation/AnnotationSupport.java

Lines changed: 58 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,17 @@
2727

2828
import java.lang.annotation.*;
2929
import java.lang.reflect.*;
30+
import java.security.AccessController;
31+
import java.security.PrivilegedAction;
3032
import java.util.ArrayList;
3133
import java.util.Arrays;
32-
import java.util.Collections;
3334
import java.util.List;
3435
import java.util.Map;
3536
import java.util.Objects;
3637

3738
import sun.misc.JavaLangAccess;
39+
import sun.reflect.LangReflectAccess;
40+
import sun.reflect.ReflectionFactory;
3841

3942
public final class AnnotationSupport {
4043
private static final JavaLangAccess LANG_ACCESS = sun.misc.SharedSecrets.getJavaLangAccess();
@@ -62,7 +65,7 @@ public final class AnnotationSupport {
6265
public static <A extends Annotation> A[] getDirectlyAndIndirectlyPresent(
6366
Map<Class<? extends Annotation>, Annotation> annotations,
6467
Class<A> annoClass) {
65-
List<A> result = new ArrayList<A>();
68+
List<A> result = new ArrayList<>();
6669

6770
@SuppressWarnings("unchecked")
6871
A direct = (A) annotations.get(annoClass);
@@ -188,27 +191,68 @@ private static <A extends Annotation> A[] getValueArray(Annotation container) {
188191
AnnotationType annoType = AnnotationType.getInstance(containerClass);
189192
if (annoType == null)
190193
throw invalidContainerException(container, null);
191-
192194
Method m = annoType.members().get("value");
193195
if (m == null)
194196
throw invalidContainerException(container, null);
195197

196-
m.setAccessible(true);
197-
198-
// This will erase to (Annotation[]) but we do a runtime cast on the
199-
// return-value in the method that call this method.
200-
@SuppressWarnings("unchecked")
201-
A[] values = (A[]) m.invoke(container);
202-
203-
return values;
204-
198+
if (Proxy.isProxyClass(container.getClass())) {
199+
// Invoke by invocation handler
200+
InvocationHandler handler = Proxy.getInvocationHandler(container);
201+
202+
try {
203+
// This will erase to (Annotation[]) but we do a runtime cast on the
204+
// return-value in the method that call this method.
205+
@SuppressWarnings("unchecked")
206+
A[] values = (A[]) handler.invoke(container, m, null);
207+
return values;
208+
} catch (Throwable t) { // from InvocationHandler::invoke
209+
throw invalidContainerException(container, t);
210+
}
211+
} else {
212+
// In theory there might be instances of Annotations that are not
213+
// implemented using Proxies. Try to invoke the "value" element with
214+
// reflection.
215+
216+
// Declaring class should be an annotation type
217+
Class<?> iface = m.getDeclaringClass();
218+
if (!iface.isAnnotation())
219+
throw new UnsupportedOperationException("Unsupported container annotation type.");
220+
// Method must be public
221+
if (!Modifier.isPublic(m.getModifiers()))
222+
throw new UnsupportedOperationException("Unsupported value member.");
223+
224+
// Interface might not be public though
225+
final Method toInvoke;
226+
if (!Modifier.isPublic(iface.getModifiers())) {
227+
if (System.getSecurityManager() != null) {
228+
toInvoke = AccessController.doPrivileged(new PrivilegedAction<Method>() {
229+
@Override
230+
public Method run() {
231+
Method res = ReflectionFactory.getReflectionFactory().leafCopyMethod(m);
232+
res.setAccessible(true);
233+
return res;
234+
}
235+
});
236+
} else {
237+
toInvoke = ReflectionFactory.getReflectionFactory().leafCopyMethod(m);
238+
toInvoke.setAccessible(true);
239+
}
240+
} else {
241+
toInvoke = m;
242+
}
243+
244+
// This will erase to (Annotation[]) but we do a runtime cast on the
245+
// return-value in the method that call this method.
246+
@SuppressWarnings("unchecked")
247+
A[] values = (A[]) toInvoke.invoke(container);
248+
249+
return values;
250+
}
205251
} catch (IllegalAccessException | // couldn't loosen security
206252
IllegalArgumentException | // parameters doesn't match
207253
InvocationTargetException | // the value method threw an exception
208254
ClassCastException e) {
209-
210255
throw invalidContainerException(container, e);
211-
212256
}
213257
}
214258

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
* Copyright (c) 2015, 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+
24+
/*
25+
* @test
26+
* @bug 8073056
27+
* @summary Repeating annotations throws java.security.AccessControlException with a SecurityManager
28+
*
29+
* @library /lib/testlibrary
30+
* @build jdk.testlibrary.Asserts
31+
* @run main CustomRepeatingWithSecurityManager
32+
* @run main/othervm CustomRepeatingWithSecurityManager "withSM"
33+
*/
34+
35+
import java.lang.annotation.*;
36+
import java.lang.reflect.*;
37+
38+
import jdk.testlibrary.Asserts;
39+
40+
public class CustomRepeatingWithSecurityManager {
41+
public static void main(String[] args) throws Exception {
42+
if (args.length == 1) {
43+
SecurityManager sm = new SecurityManager();
44+
System.setSecurityManager(sm);
45+
}
46+
47+
Asserts.assertTrue(new CustomAnnotations().getAnnotationsByType(MyAnnotation.class).length == 2,
48+
"Array should contain 2 annotations");
49+
Asserts.assertEquals(new CustomAnnotations().getAnnotationsByType(MyAnnotation.class)[1].name(),
50+
"Bar", "Should be 'Bar'");
51+
}
52+
53+
static class CustomAnnotations implements AnnotatedElement {
54+
@Override
55+
public Annotation[] getDeclaredAnnotations() {
56+
Annotation[] res = new Annotation[1];
57+
res[0] = new MyAnnotationsImpl();
58+
return res;
59+
}
60+
61+
@Override
62+
public Annotation[] getAnnotations() {
63+
return getDeclaredAnnotations();
64+
}
65+
66+
@Override
67+
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
68+
return null;
69+
}
70+
}
71+
72+
static class MyAnnotationsImpl implements MyAnnotations {
73+
public MyAnnotation[] value() {
74+
MyAnnotation[] res = new MyAnnotation[2];
75+
res[0] = new MyAnnotationImpl("Foo");
76+
res[1] = new MyAnnotationImpl("Bar");
77+
return res;
78+
}
79+
80+
@Override
81+
public Class<? extends Annotation> annotationType() {
82+
return MyAnnotations.class;
83+
}
84+
}
85+
86+
static class MyAnnotationImpl implements MyAnnotation {
87+
private String val;
88+
MyAnnotationImpl(String val) {
89+
this.val = val;
90+
}
91+
92+
public String name() { return val; }
93+
94+
@Override
95+
public Class<? extends Annotation> annotationType() {
96+
return MyAnnotations.class;
97+
}
98+
}
99+
100+
@Retention(RetentionPolicy.RUNTIME)
101+
@interface MyAnnotations {
102+
MyAnnotation[] value();
103+
}
104+
105+
@Retention(RetentionPolicy.RUNTIME)
106+
@Repeatable(MyAnnotations.class)
107+
@interface MyAnnotation {
108+
String name();
109+
}
110+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright (c) 2015, 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+
24+
/*
25+
* @test
26+
* @bug 8073056
27+
* @summary Repeating annotations throws java.security.AccessControlException with a SecurityManager
28+
*
29+
* @library /lib/testlibrary
30+
* @build jdk.testlibrary.Asserts
31+
* @run main RepeatingWithSecurityManager
32+
* @run main/othervm RepeatingWithSecurityManager "withSM"
33+
*/
34+
35+
import java.lang.annotation.*;
36+
import java.util.*;
37+
38+
import jdk.testlibrary.Asserts;
39+
40+
public class RepeatingWithSecurityManager {
41+
public static void main(String[] args) throws Exception {
42+
if (args.length == 1) {
43+
SecurityManager sm = new SecurityManager();
44+
System.setSecurityManager(sm);
45+
}
46+
47+
Asserts.assertTrue(TwoAnnotations.class.getAnnotationsByType(MyAnnotation.class).length == 2,
48+
"Array should contain 2 annotations: " +
49+
Arrays.toString(TwoAnnotations.class.getAnnotationsByType(MyAnnotation.class)));
50+
}
51+
52+
@MyAnnotation(name = "foo")
53+
@MyAnnotation(name = "bar")
54+
private static class TwoAnnotations {
55+
}
56+
57+
@Retention(RetentionPolicy.RUNTIME)
58+
@interface MyAnnotations {
59+
MyAnnotation[] value();
60+
}
61+
62+
@Retention(RetentionPolicy.RUNTIME)
63+
@Repeatable(MyAnnotations.class)
64+
@interface MyAnnotation {
65+
String name();
66+
}
67+
}

0 commit comments

Comments
 (0)