1 /* 2 * Copyright (c) 2013, 2019, 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 java.security.CodeSource; 25 import java.security.Permission; 26 import java.security.PermissionCollection; 27 import java.security.Permissions; 28 import java.security.Policy; 29 import java.security.ProtectionDomain; 30 import java.util.EnumSet; 31 import java.util.HashMap; 32 import java.util.Map; 33 import java.util.logging.LogManager; 34 import java.util.logging.Logger; 35 import java.util.logging.LoggingPermission; 36 import jdk.internal.access.JavaAWTAccess; 37 import jdk.internal.access.SharedSecrets; 38 39 /* 40 * @test 41 * @bug 8017174 8010727 8019945 42 * @summary NPE when using Logger.getAnonymousLogger or 43 * LogManager.getLogManager().getLogger 44 * 45 * @modules java.base/jdk.internal.access 46 * java.logging 47 * @run main/othervm -Dtest.security=off TestAppletLoggerContext LoadingApplet 48 * @run main/othervm -Djava.security.manager=allow -Dtest.security=on TestAppletLoggerContext LoadingApplet 49 * @run main/othervm -Dtest.security=off TestAppletLoggerContext LoadingMain 50 * @run main/othervm -Djava.security.manager=allow -Dtest.security=on TestAppletLoggerContext LoadingMain 51 * @run main/othervm -Dtest.security=off TestAppletLoggerContext One 52 * @run main/othervm -Djava.security.manager=allow -Dtest.security=on TestAppletLoggerContext One 53 * @run main/othervm -Dtest.security=off TestAppletLoggerContext Two 54 * @run main/othervm -Djava.security.manager=allow -Dtest.security=on TestAppletLoggerContext Two 55 * @run main/othervm -Dtest.security=off TestAppletLoggerContext Three 56 * @run main/othervm -Djava.security.manager=allow -Dtest.security=on TestAppletLoggerContext Three 57 * @run main/othervm -Dtest.security=off TestAppletLoggerContext Four 58 * @run main/othervm -Djava.security.manager=allow -Dtest.security=on TestAppletLoggerContext Four 59 * @run main/othervm -Dtest.security=off TestAppletLoggerContext Five 60 * @run main/othervm -Djava.security.manager=allow -Dtest.security=on TestAppletLoggerContext Five 61 * @run main/othervm -Dtest.security=off TestAppletLoggerContext Six 62 * @run main/othervm -Djava.security.manager=allow -Dtest.security=on TestAppletLoggerContext Six 63 * @run main/othervm -Dtest.security=off TestAppletLoggerContext Seven 64 * @run main/othervm -Djava.security.manager=allow -Dtest.security=on TestAppletLoggerContext Seven 65 * @run main/othervm -Dtest.security=off TestAppletLoggerContext 66 * @run main/othervm -Djava.security.manager=allow -Dtest.security=on TestAppletLoggerContext 67 */ 68 69 // NOTE: We run in other VM in order to 1. switch security manager and 2. cause 70 // LogManager class to be loaded anew. 71 public class TestAppletLoggerContext { 72 73 // Avoids the hassle of dealing with files and system props... 74 static class SimplePolicy extends Policy { 75 76 static final Policy DEFAULT_POLICY = Policy.getPolicy(); 77 78 private final Permissions perms; SimplePolicy(Permission... permissions)79 public SimplePolicy(Permission... permissions) { 80 perms = new Permissions(); 81 for (Permission permission : permissions) { 82 perms.add(permission); 83 } 84 } 85 @Override getPermissions(CodeSource cs)86 public PermissionCollection getPermissions(CodeSource cs) { 87 return perms; 88 } 89 @Override getPermissions(ProtectionDomain pd)90 public PermissionCollection getPermissions(ProtectionDomain pd) { 91 return perms; 92 } 93 @Override implies(ProtectionDomain pd, Permission p)94 public boolean implies(ProtectionDomain pd, Permission p) { 95 return perms.implies(p) || DEFAULT_POLICY.implies(pd, p); 96 } 97 } 98 99 // The bridge class initializes the logging system. 100 // It stubs the applet context in order to simulate context changes. 101 // 102 public static class Bridge { 103 104 private static class JavaAWTAccessStub implements JavaAWTAccess { 105 boolean active = true; 106 107 private static class TestExc { 108 private final Map<Object, Object> map = new HashMap<>(); put(Object key, Object v)109 void put(Object key, Object v) { map.put(key, v); } get(Object key)110 Object get(Object key) { return map.get(key); } remove(Object o)111 void remove(Object o) { map.remove(o); } exc(Object o)112 public static TestExc exc(Object o) { 113 return TestExc.class.cast(o); 114 } 115 } 116 117 TestExc exc; 118 119 @Override getAppletContext()120 public Object getAppletContext() { return active ? exc : null; } 121 } 122 123 static final JavaAWTAccessStub javaAwtAccess = new JavaAWTAccessStub(); init()124 public static void init() { 125 SharedSecrets.setJavaAWTAccess(javaAwtAccess); 126 if (System.getProperty("test.security", "on").equals("on")) { 127 Policy p = new SimplePolicy(new LoggingPermission("control", null), 128 new RuntimePermission("setContextClassLoader"), 129 new RuntimePermission("shutdownHooks")); 130 Policy.setPolicy(p); 131 System.setSecurityManager(new SecurityManager()); 132 } 133 } 134 changeContext()135 public static void changeContext() { 136 System.out.println("... Switching to a new applet context ..."); 137 javaAwtAccess.active = true; 138 javaAwtAccess.exc = new JavaAWTAccessStub.TestExc(); 139 } 140 desactivate()141 public static void desactivate() { 142 System.out.println("... Running with no applet context ..."); 143 javaAwtAccess.exc = null; 144 javaAwtAccess.active = false; 145 } 146 147 public static class CustomAnonymousLogger extends Logger { CustomAnonymousLogger()148 public CustomAnonymousLogger() { 149 this(""); 150 } CustomAnonymousLogger(String name)151 public CustomAnonymousLogger(String name) { 152 super(null, null); 153 System.out.println( " LogManager: " +LogManager.getLogManager()); 154 System.out.println( " getLogger: " +LogManager.getLogManager().getLogger(name)); 155 setParent(LogManager.getLogManager().getLogger(name)); 156 } 157 } 158 159 public static class CustomLogger extends Logger { CustomLogger(String name)160 CustomLogger(String name) { 161 super(name, null); 162 } 163 } 164 } 165 166 public static enum TestCase { 167 LoadingApplet, LoadingMain, One, Two, Three, Four, Five, Six, Seven; test()168 public void test() { 169 switch(this) { 170 // When run - each of these two tests must be 171 // run before any other tests and before each other. 172 case LoadingApplet: testLoadingApplet(); break; 173 case LoadingMain: testLoadingMain(); break; 174 case One: testOne(); break; 175 case Two: testTwo(); break; 176 case Three: testThree(); break; 177 case Four: testFour(); break; 178 case Five: testFive(); break; 179 case Six: testSix(); break; 180 case Seven: testSeven(); break; 181 } 182 } describe()183 public String describe() { 184 switch(this) { 185 case LoadingApplet: 186 return "Test that when the LogManager class is" 187 + " loaded in an applet thread first," 188 + "\n all LoggerContexts are correctly initialized"; 189 case LoadingMain: 190 return "Test that when the LogManager class is" 191 + " loaded in the main thread first," 192 + "\n all LoggerContexts are correctly initialized"; 193 case One: 194 return "Test that Logger.getAnonymousLogger()" 195 + " and new CustomAnonymousLogger() don't throw NPE"; 196 case Two: 197 return "Test that Logger.getLogger(\"\")" 198 + " does not return null nor throws NPE"; 199 case Three: 200 return "Test that LogManager.getLogManager().getLogger(\"\")" 201 + " does not return null nor throws NPE"; 202 case Four: 203 return "Test that Logger.getLogger(Logger.GLOBAL_LOGGER_NAME)" 204 + " does not return null,\n and that" 205 + " new CustomAnonymousLogger(Logger.GLOBAL_LOGGER_NAME)" 206 + " does not throw NPE"; 207 case Five: 208 return "Test that LogManager.getLogManager().getLogger(Logger.GLOBAL_LOGGER_NAME)" 209 + "\n does not return null nor throws NPE"; 210 case Six: 211 return "Test that manager.getLogger(Logger.GLOBAL_LOGGER_NAME)" 212 + " returns null\n when manager is not the default" 213 + " LogManager instance.\n" 214 + "Test adding a new logger named \"global\" in that" 215 + " non default instance."; 216 case Seven: return "Test that manager.getLogger(\"\")" 217 + " returns null\n when manager is not the default" 218 + " LogManager instance.\n" 219 + "Test adding a new logger named \"\" in that" 220 + " non default instance."; 221 default: return "Undefined"; 222 } 223 } 224 }; 225 226 /** 227 * @param args the command line arguments 228 */ main(String[] args)229 public static void main(String[] args) { 230 Bridge.init(); 231 EnumSet<TestCase> tests = EnumSet.noneOf(TestCase.class); 232 for (String arg : args) { 233 tests.add(TestCase.valueOf(arg)); 234 } 235 if (args.length == 0) { 236 tests = EnumSet.complementOf(EnumSet.of(TestCase.LoadingMain)); 237 } 238 final EnumSet<TestCase> loadingTests = 239 EnumSet.of(TestCase.LoadingApplet, TestCase.LoadingMain); 240 int testrun = 0; 241 for (TestCase test : tests) { 242 if (loadingTests.contains(test)) { 243 if (testrun > 0) { 244 throw new UnsupportedOperationException("Test case " 245 + test + " must be executed first!"); 246 } 247 } 248 System.out.println("Testing "+ test+": "); 249 System.out.println(test.describe()); 250 try { 251 test.test(); 252 } catch (Exception x) { 253 throw new Error(String.valueOf(test) 254 + (System.getSecurityManager() == null ? " without " : " with ") 255 + "security failed: "+x+"\n "+"FAILED: "+test.describe()+"\n", x); 256 } finally { 257 testrun++; 258 } 259 Bridge.changeContext(); 260 System.out.println("PASSED: "+ test); 261 } 262 } 263 testLoadingApplet()264 public static void testLoadingApplet() { 265 Bridge.changeContext(); 266 267 Logger bar = new Bridge.CustomLogger("com.foo.Bar"); 268 LogManager.getLogManager().addLogger(bar); 269 assertNotNull(bar.getParent()); 270 testParent(bar); 271 testParent(LogManager.getLogManager().getLogger("global")); 272 testParent(LogManager.getLogManager().getLogger(bar.getName())); 273 274 Bridge.desactivate(); 275 276 Logger foo = new Bridge.CustomLogger("com.foo.Foo"); 277 boolean b = LogManager.getLogManager().addLogger(foo); 278 assertEquals(Boolean.TRUE, Boolean.valueOf(b)); 279 assertNotNull(foo.getParent()); 280 testParent(foo); 281 testParent(LogManager.getLogManager().getLogger("global")); 282 testParent(LogManager.getLogManager().getLogger(foo.getName())); 283 } 284 testLoadingMain()285 public static void testLoadingMain() { 286 Bridge.desactivate(); 287 288 Logger bar = new Bridge.CustomLogger("com.foo.Bar"); 289 LogManager.getLogManager().addLogger(bar); 290 assertNotNull(bar.getParent()); 291 testParent(bar); 292 testParent(LogManager.getLogManager().getLogger("global")); 293 testParent(LogManager.getLogManager().getLogger(bar.getName())); 294 295 Bridge.changeContext(); 296 297 Logger foo = new Bridge.CustomLogger("com.foo.Foo"); 298 boolean b = LogManager.getLogManager().addLogger(foo); 299 assertEquals(Boolean.TRUE, Boolean.valueOf(b)); 300 assertNotNull(foo.getParent()); 301 testParent(foo); 302 testParent(LogManager.getLogManager().getLogger("global")); 303 testParent(LogManager.getLogManager().getLogger(foo.getName())); 304 305 } 306 testOne()307 public static void testOne() { 308 for (int i=0; i<3 ; i++) { 309 Logger logger1 = Logger.getAnonymousLogger(); 310 Logger logger1b = Logger.getAnonymousLogger(); 311 Bridge.changeContext(); 312 Logger logger2 = Logger.getAnonymousLogger(); 313 Logger logger2b = Logger.getAnonymousLogger(); 314 Bridge.changeContext(); 315 Logger logger3 = new Bridge.CustomAnonymousLogger(); 316 Logger logger3b = new Bridge.CustomAnonymousLogger(); 317 Bridge.changeContext(); 318 Logger logger4 = new Bridge.CustomAnonymousLogger(); 319 Logger logger4b = new Bridge.CustomAnonymousLogger(); 320 } 321 } 322 323 testTwo()324 public static void testTwo() { 325 for (int i=0; i<3 ; i++) { 326 Logger logger1 = Logger.getLogger(""); 327 Logger logger1b = Logger.getLogger(""); 328 assertNotNull(logger1); 329 assertNotNull(logger1b); 330 assertEquals(logger1, logger1b); 331 Bridge.changeContext(); 332 Logger logger2 = Logger.getLogger(""); 333 Logger logger2b = Logger.getLogger(""); 334 assertNotNull(logger2); 335 assertNotNull(logger2b); 336 assertEquals(logger2, logger2b); 337 assertEquals(logger1, logger2); 338 } 339 } 340 testThree()341 public static void testThree() { 342 for (int i=0; i<3 ; i++) { 343 Logger logger1 = LogManager.getLogManager().getLogger(""); 344 Logger logger1b = LogManager.getLogManager().getLogger(""); 345 assertNotNull(logger1); 346 assertNotNull(logger1b); 347 assertEquals(logger1, logger1b); 348 Bridge.changeContext(); 349 Logger logger2 = LogManager.getLogManager().getLogger(""); 350 Logger logger2b = LogManager.getLogManager().getLogger(""); 351 assertNotNull(logger2); 352 assertNotNull(logger2b); 353 assertEquals(logger2, logger2b); 354 assertEquals(logger1, logger2); 355 } 356 } 357 testFour()358 public static void testFour() { 359 for (int i=0; i<3 ; i++) { 360 Logger logger1 = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); 361 Logger logger1b = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); 362 assertNotNull(logger1); 363 assertNotNull(logger1b); 364 assertEquals(logger1, logger1b); 365 Bridge.changeContext(); 366 367 Logger logger2 = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); 368 Logger logger2b = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); 369 assertNotNull(logger2); 370 assertNotNull(logger2b); 371 assertEquals(logger2, logger2b); 372 373 assertEquals(logger1, logger2); 374 375 Bridge.changeContext(); 376 Logger logger3 = new Bridge.CustomAnonymousLogger(Logger.GLOBAL_LOGGER_NAME); 377 Logger logger3b = new Bridge.CustomAnonymousLogger(Logger.GLOBAL_LOGGER_NAME); 378 Bridge.changeContext(); 379 Logger logger4 = new Bridge.CustomAnonymousLogger(Logger.GLOBAL_LOGGER_NAME); 380 Logger logger4b = new Bridge.CustomAnonymousLogger(Logger.GLOBAL_LOGGER_NAME); 381 } 382 } 383 testFive()384 public static void testFive() { 385 for (int i=0; i<3 ; i++) { 386 Logger logger1 = LogManager.getLogManager().getLogger(Logger.GLOBAL_LOGGER_NAME); 387 Logger logger1b = LogManager.getLogManager().getLogger(Logger.GLOBAL_LOGGER_NAME); 388 assertNotNull(logger1); 389 assertNotNull(logger1b); 390 assertEquals(logger1, logger1b); 391 392 Bridge.changeContext(); 393 394 Logger logger2 = LogManager.getLogManager().getLogger(Logger.GLOBAL_LOGGER_NAME); 395 Logger logger2b = LogManager.getLogManager().getLogger(Logger.GLOBAL_LOGGER_NAME); 396 assertNotNull(logger2); 397 assertNotNull(logger2b); 398 assertEquals(logger2, logger2b); 399 400 assertEquals(logger1, logger2); 401 } 402 } 403 404 /** 405 * This test is designed to test the behavior of additional LogManager instances. 406 * It must be noted that if the security manager is off, then calling 407 * Bridge.changeContext() has actually no effect - which explains why we have 408 * some differences between the cases security manager on & security manager 409 * off. 410 **/ testSix()411 public static void testSix() { 412 for (int i=0; i<3 ; i++) { 413 Bridge.desactivate(); 414 LogManager manager = new LogManager() {}; 415 Logger logger1 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); 416 Logger logger1b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); 417 assertNull(logger1); 418 assertNull(logger1b); 419 Logger global = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME); 420 manager.addLogger(global); 421 Logger logger2 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); 422 Logger logger2b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); 423 assertNotNull(logger2); 424 assertNotNull(logger2b); 425 assertEquals(logger2, global); 426 assertEquals(logger2b, global); 427 assertNull(manager.getLogger("")); 428 assertNull(manager.getLogger("")); 429 430 for (int j = 0; j<3; j++) { 431 Bridge.changeContext(); 432 433 // this is not a supported configuration: 434 // We are in an applet context with several log managers. 435 // We however need to check our assumptions... 436 437 // Applet context => root logger and global logger should also be null. 438 439 Logger expected = (System.getSecurityManager() == null ? global : null); 440 Logger logger3 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); 441 Logger logger3b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); 442 assertEquals(expected, logger3); 443 assertEquals(expected, logger3b); 444 Logger global2 = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME); 445 manager.addLogger(global2); 446 Logger logger4 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); 447 Logger logger4b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); 448 assertNotNull(logger4); 449 assertNotNull(logger4b); 450 expected = (System.getSecurityManager() == null ? global : global2);; 451 assertEquals(logger4, expected); 452 assertEquals(logger4b, expected); 453 454 Logger logger5 = manager.getLogger(""); 455 Logger logger5b = manager.getLogger(""); 456 Logger expectedRoot = null; 457 assertEquals(logger5, expectedRoot); 458 assertEquals(logger5b, expectedRoot); 459 } 460 461 } 462 } 463 464 /** 465 * This test is designed to test the behavior of additional LogManager instances. 466 * It must be noted that if the security manager is off, then calling 467 * Bridge.changeContext() has actually no effect - which explains why we have 468 * some differences between the cases security manager on & security manager 469 * off. 470 **/ testSeven()471 public static void testSeven() { 472 for (int i=0; i<3 ; i++) { 473 Bridge.desactivate(); 474 LogManager manager = new LogManager() {}; 475 Logger logger1 = manager.getLogger(""); 476 Logger logger1b = manager.getLogger(""); 477 assertNull(logger1); 478 assertNull(logger1b); 479 Logger global = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME); 480 manager.addLogger(global); 481 Logger logger2 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); 482 Logger logger2b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); 483 assertNotNull(logger2); 484 assertNotNull(logger2b); 485 assertEquals(logger2, global); 486 assertEquals(logger2b, global); 487 Logger logger3 = manager.getLogger(""); 488 Logger logger3b = manager.getLogger(""); 489 assertNull(logger3); 490 assertNull(logger3b); 491 Logger root = new Bridge.CustomLogger(""); 492 manager.addLogger(root); 493 Logger logger4 = manager.getLogger(""); 494 Logger logger4b = manager.getLogger(""); 495 assertNotNull(logger4); 496 assertNotNull(logger4b); 497 assertEquals(logger4, root); 498 assertEquals(logger4b, root); 499 500 for (int j = 0 ; j < 3 ; j++) { 501 Bridge.changeContext(); 502 503 // this is not a supported configuration: 504 // We are in an applet context with several log managers. 505 // We however need to check our assumptions... 506 507 // Applet context => root logger and global logger should also be null. 508 509 Logger logger5 = manager.getLogger(""); 510 Logger logger5b = manager.getLogger(""); 511 Logger expectedRoot = (System.getSecurityManager() == null ? root : null); 512 assertEquals(logger5, expectedRoot); 513 assertEquals(logger5b, expectedRoot); 514 515 if (System.getSecurityManager() != null) { 516 assertNull(manager.getLogger(Logger.GLOBAL_LOGGER_NAME)); 517 } else { 518 assertEquals(global, manager.getLogger(Logger.GLOBAL_LOGGER_NAME)); 519 } 520 521 Logger global2 = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME); 522 manager.addLogger(global2); 523 Logger logger6 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); 524 Logger logger6b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME); 525 Logger expectedGlobal = (System.getSecurityManager() == null ? global : global2); 526 527 assertNotNull(logger6); 528 assertNotNull(logger6b); 529 assertEquals(logger6, expectedGlobal); 530 assertEquals(logger6b, expectedGlobal); 531 if (System.getSecurityManager() != null) { 532 assertNull(manager.getLogger("")); 533 } else { 534 assertEquals(root, manager.getLogger("")); 535 } 536 537 Logger root2 = new Bridge.CustomLogger(""); 538 manager.addLogger(root2); 539 expectedRoot = (System.getSecurityManager() == null ? root : root2); 540 Logger logger7 = manager.getLogger(""); 541 Logger logger7b = manager.getLogger(""); 542 assertNotNull(logger7); 543 assertNotNull(logger7b); 544 assertEquals(logger7, expectedRoot); 545 assertEquals(logger7b, expectedRoot); 546 } 547 } 548 } 549 testParent(Logger logger)550 public static void testParent(Logger logger) { 551 Logger l = logger; 552 while (l.getParent() != null) { 553 l = l.getParent(); 554 } 555 assertEquals("", l.getName()); 556 } 557 558 public static class TestError extends RuntimeException { TestError(String msg)559 public TestError(String msg) { 560 super(msg); 561 } 562 } 563 assertNotNull(Object obj)564 public static void assertNotNull(Object obj) { 565 if (obj == null) throw new NullPointerException(); 566 } 567 assertNull(Object obj)568 public static void assertNull(Object obj) { 569 if (obj != null) throw new TestError("Null expected, got "+obj); 570 } 571 assertEquals(Object o1, Object o2)572 public static void assertEquals(Object o1, Object o2) { 573 if (o1 != o2) { 574 throw new TestError(o1 + " != " + o2); 575 } 576 } 577 assertNotEquals(Object o1, Object o2)578 public static void assertNotEquals(Object o1, Object o2) { 579 if (o1 == o2) { 580 throw new TestError(o1 + " == " + o2); 581 } 582 } 583 } 584