1 /* 2 * Copyright (c) 2023, 2024, 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 import jdk.test.lib.Asserts; 25 import java.lang.management.ManagementFactory; 26 import java.lang.management.RuntimeMXBean; 27 import java.lang.reflect.Method; 28 import java.lang.reflect.Field; 29 import java.util.List; 30 import jdk.internal.misc.Unsafe; 31 import jdk.internal.vm.annotation.NullRestricted; 32 import jdk.internal.vm.annotation.LooselyConsistentValue; 33 import jdk.internal.vm.annotation.Strict; 34 35 36 37 38 39 /* 40 * @test 41 * @summary Test of NullRestricted, Strict and LooselyConsistentValue annotations 42 * @modules java.base/jdk.internal.misc 43 * java.base/jdk.internal.vm.annotation 44 * @library /test/lib 45 * @enablePreview 46 * @compile AnnotationsTests.java 47 * @run main/othervm AnnotationsTests 48 */ 49 50 51 public class AnnotationsTests { 52 53 private static final Unsafe UNSAFE = Unsafe.getUnsafe(); 54 static boolean nullableLayoutEnabled; 55 56 public static void main(String[] args) { 57 RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean(); 58 List<String> arguments = runtimeMxBean.getInputArguments(); 59 nullableLayoutEnabled = arguments.contains("-XX:+UseNullableValueFlattening"); 60 AnnotationsTests tests = new AnnotationsTests(); 61 Class c = tests.getClass(); 62 for (Method m : c.getDeclaredMethods()) { 63 if (m.getName().startsWith("test_")) { 64 try { 65 System.out.println("Running " + m.getName()); 66 m.invoke(tests); 67 } catch (Throwable t) { 68 t.printStackTrace(); 69 throw new RuntimeException(t); 70 } 71 } 72 } 73 } 74 75 static class BadClass0 { 76 @Strict 77 @NullRestricted 78 String s = new String("bad"); 79 } 80 81 // Test detection of illegal usage of NullRestricted on an identity field 82 void test_0() { 83 Throwable exception = null; 84 try { 85 BadClass0 bc = new BadClass0(); 86 } catch (IncompatibleClassChangeError e) { 87 exception = e; 88 System.out.println("Received " + e); 89 } 90 Asserts.assertNotNull(exception, "Failed to detect illegal use of @NullRestricted"); 91 } 92 93 // Test detection of non-static field annotated with @NullRestricted but not @Strict 94 static value class ValueClass1 { 95 int i = 0; 96 int j = 0; 97 } 98 99 static class BadClass1 { 100 @NullRestricted 101 ValueClass1 vc; 102 } 103 104 void test_1() { 105 Throwable exception = null; 106 try { 107 BadClass1 tc = new BadClass1(); 108 } catch (ClassFormatError e) { 109 exception = e; 110 System.out.println("Received " + e); 111 } 112 Asserts.assertNotNull(exception, "Failed to detect illegal use of @NullRestricted without @Strict on a non-static field"); 113 } 114 115 // Invalid usage of @NullRestricted on a non-strict non-static field 116 static value class ValueClass2 { 117 int i = 0; 118 int j = 0; 119 } 120 121 static class BadClass2 { 122 @NullRestricted 123 static ValueClass2 val; 124 } 125 126 void test_2() { 127 Throwable exception = null; 128 try { 129 BadClass2 tc = new BadClass2(); 130 } catch (ClassFormatError e) { 131 exception = e; 132 System.out.println("Received " + e); 133 } 134 Asserts.assertNotNull(exception, "FFailed to detect illegal use of @NullRestricted without @Strict on a static field"); 135 } 136 137 // Test invalid usage of @LooselyConsistentValue on an identity class 138 @LooselyConsistentValue 139 static class BadClass4 { 140 141 } 142 143 void test_4() { 144 Throwable exception = null; 145 try { 146 BadClass4 tc = new BadClass4(); 147 } catch (ClassFormatError e) { 148 exception = e; 149 System.out.println("Received " + e); 150 } 151 Asserts.assertNotNull(exception, "Failed to detect illegal use of @LooselyConsistentValue"); 152 } 153 154 // Test field flattening of @NullRestricted annotated fields 155 156 @LooselyConsistentValue 157 static value class ValueClass5 { 158 int i = 0; 159 } 160 161 static class GoodClass5 { 162 ValueClass5 f0 = new ValueClass5(); 163 164 @Strict 165 @NullRestricted 166 ValueClass5 f1 = new ValueClass5(); 167 } 168 169 void test_5() { 170 Throwable exception = null; 171 try { 172 GoodClass5 vc = new GoodClass5(); 173 Field f0 = vc.getClass().getDeclaredField("f0"); 174 if (nullableLayoutEnabled) { 175 Asserts.assertTrue(UNSAFE.isFlatField(f0), "Flat field expected, but field is not flat"); 176 } else { 177 Asserts.assertFalse(UNSAFE.isFlatField(f0), "Unexpected flat field"); 178 } 179 Field f1 = vc.getClass().getDeclaredField("f1"); 180 Asserts.assertTrue(UNSAFE.isFlatField(f1), "Flat field expected, but field is not flat"); 181 } catch (IncompatibleClassChangeError e) { 182 exception = e; 183 System.out.println("Received " + e); 184 } catch(NoSuchFieldException e) { 185 Asserts.fail("Test error"); 186 } 187 Asserts.assertNull(exception, "Unexpected exception: " + exception); 188 } 189 190 191 // Test detection/handling of circularity 192 193 static value class ValueClass6a { 194 @Strict 195 @NullRestricted 196 ValueClass6b val = new ValueClass6b(); 197 } 198 199 static value class ValueClass6b { 200 @Strict 201 @NullRestricted 202 ValueClass6a val = new ValueClass6a(); 203 } 204 205 static class BadClass6 { 206 @Strict 207 @NullRestricted 208 ValueClass6a val = new ValueClass6a(); 209 } 210 211 void test_6() { 212 Throwable exception = null; 213 try { 214 BadClass6 bc = new BadClass6(); 215 } catch (ClassCircularityError e) { 216 exception = e; 217 System.out.println("Received " + e); 218 } 219 Asserts.assertNotNull(exception, "Failed to detect circularity"); 220 } 221 222 // Test null restricted static field 223 static value class ValueClass7 { 224 int i = 0; 225 } 226 227 static class GoodClass7 { 228 @Strict 229 @NullRestricted 230 static ValueClass7 sval = new ValueClass7(); 231 } 232 233 void test_7() { 234 Throwable exception = null; 235 try { 236 ValueClass7 val = GoodClass7.sval; 237 Asserts.assertNotNull(val, "Unexpected null value"); 238 } catch (Throwable e) { 239 exception = e; 240 System.out.println("Received " + e); 241 } 242 Asserts.assertNull(exception, "Unexpected exception: " + exception); 243 } 244 245 // Test circularity on static fields 246 static value class ValueClass8 { 247 @Strict 248 @NullRestricted 249 static ValueClass8 sval = new ValueClass8(); 250 } 251 252 void test_8() { 253 Throwable exception = null; 254 try { 255 ValueClass8 val = ValueClass8.sval; 256 Asserts.assertNotNull(val, "Unexpected null value"); 257 } catch (Throwable e) { 258 exception = e; 259 System.out.println("Received " + e); 260 } 261 Asserts.assertNull(exception, "Unexpected exception: " + exception); 262 } 263 264 // Test that writing null to a @NullRestricted non-static field throws an exception 265 static value class ValueClass9 { 266 int i = 0; 267 } 268 269 static class GoodClass9 { 270 @Strict 271 @NullRestricted 272 ValueClass9 val = new ValueClass9(); 273 } 274 275 void test_9() { 276 Throwable exception = null; 277 try { 278 GoodClass9 gc = new GoodClass9(); 279 gc.val = null; 280 } catch(NullPointerException e) { 281 exception = e; 282 System.out.println("Received " + e); 283 } 284 Asserts.assertNotNull(exception, "Expected NullPointerException not received"); 285 } 286 287 // Test that writing null to a @NullRestricted static field throws an exception 288 static value class ValueClass10 { 289 @Strict 290 @NullRestricted 291 static ValueClass10 sval = new ValueClass10(); 292 } 293 294 void test_10() { 295 Throwable exception = null; 296 try { 297 ValueClass10.sval = null; 298 } catch(NullPointerException e) { 299 exception = e; 300 System.out.println("Received " + e); 301 } 302 Asserts.assertNotNull(exception, "Expected NullPointerException not received"); 303 } 304 305 // Test static null restricted field that is not declared strict 306 static value class ValueClass11 { 307 int i = 0; 308 int j = 0; 309 } 310 311 static class BadClass11 { 312 @NullRestricted 313 static ValueClass11 val = new ValueClass11(); 314 } 315 316 void test_11() { 317 Throwable exception = null; 318 try { 319 ValueClass11 val = BadClass11.val; 320 System.out.println(val); 321 } catch(ClassFormatError e) { 322 exception = e; 323 System.out.println("Received " + e); 324 } 325 Asserts.assertNotNull(exception, "Expected ClassFormatError not received"); 326 } 327 328 // Test illegal use of @NullRestricted on a primitive field 329 static class BadClass12 { 330 @Strict 331 @NullRestricted 332 int i = 0; 333 } 334 void test_12() { 335 Throwable exception = null; 336 try { 337 BadClass12 val = new BadClass12(); 338 System.out.println(val); 339 } catch(ClassFormatError e) { 340 exception = e; 341 System.out.println("Received " + e); 342 } 343 Asserts.assertNotNull(exception, "Expected ClassFormatError not received"); 344 } 345 346 // Test illegal use of @NullRestricted on an array field 347 static class BadClass13 { 348 @Strict 349 @NullRestricted 350 int[] intArray = new int[1]; 351 } 352 void test_13() { 353 Throwable exception = null; 354 try { 355 BadClass13 val = new BadClass13(); 356 System.out.println(val); 357 } catch(ClassFormatError e) { 358 exception = e; 359 System.out.println("Received " + e); 360 } 361 Asserts.assertNotNull(exception, "Expected ClassFormatError not received"); 362 } 363 364 } 365