1 /*
2  * Copyright (c) 2012, 2017, 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 7103570 8189291
27  * @author David Holmes
28  * @run main/othervm AtomicUpdaters
29  * @run main/othervm AtomicUpdaters UseSM
30  * @summary Checks the (in)ability to create field updaters for differently
31  *          accessible fields in different locations with/without a security
32  *          manager
33  */
34 
35 import java.lang.reflect.Field;
36 import java.security.AccessControlException;
37 import java.security.CodeSource;
38 import java.security.Permission;
39 import java.security.PermissionCollection;
40 import java.security.Policy;
41 import java.security.ProtectionDomain;
42 import java.util.concurrent.atomic.AtomicInteger;
43 import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
44 import java.util.concurrent.atomic.AtomicLong;
45 import java.util.concurrent.atomic.AtomicLongFieldUpdater;
46 import java.util.concurrent.atomic.AtomicReference;
47 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
48 
49 public class  AtomicUpdaters {
50     static final Policy DEFAULT_POLICY = Policy.getPolicy();
51 
52     enum TYPE { INT, LONG, REF }
53 
54     static class Config {
55         final Class<?> clazz;
56         final String field;
57         final String access;
58         final boolean reflectOk;
59         final boolean updaterOk;
60         final String desc;
61         final TYPE type;
62 
Config(Class<?> clazz, String field, String access, boolean reflectOk, boolean updaterOk, String desc, TYPE type)63         Config(Class<?> clazz, String field, String access,
64                boolean reflectOk, boolean updaterOk, String desc, TYPE type) {
65             this.clazz = clazz;
66             this.field = field;
67             this.access = access;
68             this.reflectOk = reflectOk;
69             this.updaterOk = updaterOk;
70             this.desc = desc;
71             this.type =type;
72         }
73 
toString()74         public String toString() {
75             return desc + ": " + access + " " + clazz.getName() + "." + field;
76         }
77     }
78 
79     static Config[] tests;
80 
initTests(boolean hasSM)81     static void initTests(boolean hasSM) {
82         tests = new Config[] {
83             new Config(AtomicUpdaters.class, "pub_int", "public", true, true, "public int field of current class", TYPE.INT),
84             new Config(AtomicUpdaters.class, "priv_int", "private", true, true, "private int field of current class", TYPE.INT),
85             new Config(AtomicUpdaters.class, "pub_long", "public", true, true, "public long field of current class", TYPE.LONG),
86             new Config(AtomicUpdaters.class, "priv_long", "private", true, true, "private long field of current class", TYPE.LONG),
87             new Config(AtomicUpdaters.class, "pub_ref", "public", true, true, "public ref field of current class", TYPE.REF),
88             new Config(AtomicUpdaters.class, "priv_ref", "private", true, true, "private ref field of current class", TYPE.REF),
89 
90             // Would like to test a public volatile in a class in another
91             // package - but of course there aren't any
92             new Config(AtomicInteger.class, "value", "private", !hasSM, false, "private int field of class in different package", TYPE.INT),
93             new Config(AtomicLong.class, "value", "private", !hasSM, false, "private long field of class in different package", TYPE.LONG),
94             new Config(AtomicReference.class, "value", "private", !hasSM, false, "private reference field of class in different package", TYPE.REF),
95         };
96     }
97 
98     public volatile int pub_int;
99     private volatile int priv_int;
100     public volatile long pub_long;
101     private volatile long priv_long;
102     public volatile Object pub_ref;
103     private volatile Object priv_ref;
104 
105 
106     // This should be set dynamically at runtime using a System property, but
107     // ironically we get a SecurityException if we try to do that with a
108     // SecurityManager installed
109     static boolean verbose;
110 
main(String[] args)111     public static void main(String[] args) throws Throwable {
112         boolean hasSM = false;
113         for (String arg : args) {
114             if ("-v".equals(arg)) {
115                 verbose = true;
116             }
117             else if ("UseSM".equals(arg)) {
118                 // Ensure that the test is not influenced by the default users policy.
119                 Policy.setPolicy(new NoPermissionsPolicy());
120                 SecurityManager m = System.getSecurityManager();
121                 if (m != null)
122                     throw new RuntimeException("No security manager should initially be installed");
123                 System.setSecurityManager(new java.lang.SecurityManager());
124                 hasSM = true;
125             }
126             else {
127                 throw new IllegalArgumentException("Unexpected option: " + arg);
128             }
129         }
130         initTests(hasSM);
131 
132         int failures = 0;
133 
134         System.out.printf("Testing with%s a SecurityManager present\n", hasSM ? "" : "out");
135         for (Config c : tests) {
136             System.out.println("Testing: " + c);
137             Error reflectionFailure = null;
138             Error updaterFailure = null;
139             Class<?> clazz = c.clazz;
140             // See if we can reflectively access the field
141             System.out.println(" - testing getDeclaredField");
142             try {
143                 Field f = clazz.getDeclaredField(c.field);
144                 if (!c.reflectOk)
145                     reflectionFailure = new Error("Unexpected reflective access: " + c);
146             }
147             catch (AccessControlException e) {
148                 if (c.reflectOk)
149                     reflectionFailure = new Error("Unexpected reflective access failure: " + c, e);
150                 else if (verbose) {
151                     System.out.println("Got expected reflection exception: " + e);
152                     e.printStackTrace(System.out);
153                 }
154             }
155 
156             if (reflectionFailure != null) {
157                 reflectionFailure.printStackTrace(System.out);
158             }
159 
160             // see if we can create an atomic updater for the field
161             Object u = null;
162             try {
163                 switch (c.type) {
164                 case INT:
165                     System.out.println(" - testing AtomicIntegerFieldUpdater");
166                     u = AtomicIntegerFieldUpdater.newUpdater(clazz, c.field);
167                     break;
168                 case LONG:
169                     System.out.println(" - testing AtomicLongFieldUpdater");
170                     u = AtomicLongFieldUpdater.newUpdater(clazz, c.field);
171                     break;
172                 case REF:
173                     System.out.println(" - testing AtomicReferenceFieldUpdater");
174                     u = AtomicReferenceFieldUpdater.newUpdater(clazz, Object.class, c.field);
175                     break;
176                 }
177 
178                 if (!c.updaterOk)
179                     updaterFailure =  new Error("Unexpected updater access: " + c);
180             }
181             catch (Exception e) {
182                 if (c.updaterOk)
183                     updaterFailure = new Error("Unexpected updater access failure: " + c, e);
184                 else if (verbose) {
185                     System.out.println("Got expected updater exception: " + e);
186                     e.printStackTrace(System.out);
187                 }
188             }
189 
190             if (updaterFailure != null) {
191                 updaterFailure.printStackTrace(System.out);
192             }
193 
194             if (updaterFailure != null || reflectionFailure != null) {
195                 failures++;
196 
197             }
198         }
199 
200         if (failures > 0) {
201             throw new Error("Some tests failed - see previous stacktraces");
202         }
203     }
204 
205     /**
206      * Policy with no permissions.
207      */
208     private static class NoPermissionsPolicy extends Policy {
209         @Override
getPermissions(CodeSource cs)210         public PermissionCollection getPermissions(CodeSource cs) {
211             return Policy.UNSUPPORTED_EMPTY_COLLECTION;
212         }
213 
214         @Override
getPermissions(ProtectionDomain pd)215         public PermissionCollection getPermissions(ProtectionDomain pd) {
216             return Policy.UNSUPPORTED_EMPTY_COLLECTION;
217         }
218 
219         @Override
implies(ProtectionDomain pd, Permission p)220         public boolean implies(ProtectionDomain pd, Permission p) {
221             return Policy.UNSUPPORTED_EMPTY_COLLECTION.implies(p) ||
222                     DEFAULT_POLICY.implies(pd, p);
223         }
224     }
225 }
226