1 /* 2 * Copyright (c) 2015, 2020, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.internal.loader; 27 28 import java.io.IOException; 29 import java.io.InputStream; 30 import java.lang.module.ModuleDescriptor; 31 import java.lang.module.ModuleReference; 32 import java.lang.module.ModuleReader; 33 import java.lang.ref.SoftReference; 34 import java.net.MalformedURLException; 35 import java.net.URI; 36 import java.net.URL; 37 import java.nio.ByteBuffer; 38 import java.security.AccessController; 39 import java.security.CodeSigner; 40 import java.security.CodeSource; 41 import java.security.PermissionCollection; 42 import java.security.PrivilegedAction; 43 import java.security.PrivilegedActionException; 44 import java.security.PrivilegedExceptionAction; 45 import java.security.SecureClassLoader; 46 import java.util.ArrayList; 47 import java.util.Collections; 48 import java.util.Enumeration; 49 import java.util.Iterator; 50 import java.util.List; 51 import java.util.Map; 52 import java.util.NoSuchElementException; 53 import java.util.Optional; 54 import java.util.concurrent.ConcurrentHashMap; 55 import java.util.function.Function; 56 import java.util.jar.Attributes; 57 import java.util.jar.Manifest; 58 import java.util.stream.Stream; 59 60 import jdk.internal.access.SharedSecrets; 61 import jdk.internal.misc.VM; 62 import jdk.internal.module.ModulePatcher.PatchedModuleReader; 63 import jdk.internal.module.Resources; 64 import jdk.internal.vm.annotation.Stable; 65 import sun.security.util.LazyCodeSourcePermissionCollection; 66 67 68 /** 69 * The platform or application class loader. Resources loaded from modules 70 * defined to the boot class loader are also loaded via an instance of this 71 * ClassLoader type. 72 * 73 * <p> This ClassLoader supports loading of classes and resources from modules. 74 * Modules are defined to the ClassLoader by invoking the {@link #loadModule} 75 * method. Defining a module to this ClassLoader has the effect of making the 76 * types in the module visible. </p> 77 * 78 * <p> This ClassLoader also supports loading of classes and resources from a 79 * class path of URLs that are specified to the ClassLoader at construction 80 * time. The class path may expand at runtime (the Class-Path attribute in JAR 81 * files or via instrumentation agents). </p> 82 * 83 * <p> The delegation model used by this ClassLoader differs to the regular 84 * delegation model. When requested to load a class then this ClassLoader first 85 * maps the class name to its package name. If there is a module defined to a 86 * BuiltinClassLoader containing this package then the class loader delegates 87 * directly to that class loader. If there isn't a module containing the 88 * package then it delegates the search to the parent class loader and if not 89 * found in the parent then it searches the class path. The main difference 90 * between this and the usual delegation model is that it allows the platform 91 * class loader to delegate to the application class loader, important with 92 * upgraded modules defined to the platform class loader. 93 */ 94 95 public class BuiltinClassLoader 96 extends SecureClassLoader 97 { 98 static { 99 if (!ClassLoader.registerAsParallelCapable()) 100 throw new InternalError("Unable to register as parallel capable"); 101 } 102 103 // parent ClassLoader 104 private final BuiltinClassLoader parent; 105 106 // the URL class path, or null if there is no class path 107 private @Stable URLClassPath ucp; 108 109 void setClassPath(URLClassPath ucp) { 110 this.ucp = ucp; 111 } 112 113 /** 114 * A module defined/loaded by a built-in class loader. 115 * 116 * A LoadedModule encapsulates a ModuleReference along with its CodeSource 117 * URL to avoid needing to create this URL when defining classes. 118 */ 119 private static class LoadedModule { 120 private final BuiltinClassLoader loader; 121 private final ModuleReference mref; 122 private final URI uri; // may be null 123 private @Stable URL codeSourceURL; // may be null 124 125 LoadedModule(BuiltinClassLoader loader, ModuleReference mref) { 126 URL url = null; 127 this.uri = mref.location().orElse(null); 128 129 // for non-jrt schemes we need to resolve the codeSourceURL 130 // eagerly during bootstrap since the handler might be 131 // overridden 132 if (uri != null && !"jrt".equals(uri.getScheme())) { 133 url = createURL(uri); 134 } 135 this.loader = loader; 136 this.mref = mref; 137 this.codeSourceURL = url; 138 } 139 140 BuiltinClassLoader loader() { return loader; } 141 ModuleReference mref() { return mref; } 142 String name() { return mref.descriptor().name(); } 143 144 URL codeSourceURL() { 145 URL url = codeSourceURL; 146 if (url == null && uri != null) { 147 codeSourceURL = url = createURL(uri); 148 } 149 return url; 150 } 151 152 private URL createURL(URI uri) { 153 URL url = null; 154 try { 155 url = uri.toURL(); 156 } catch (MalformedURLException | IllegalArgumentException e) { 157 } 158 return url; 159 } 160 } 161 162 static class ArchivedData { 163 static Map<String, LoadedModule> packageToModule; 164 } 165 166 // maps package name to loaded module for modules in the boot layer 167 private static final Map<String, LoadedModule> packageToModule; 168 169 static { 170 VM.initializeFromArchive(ArchivedData.class); 171 if (ArchivedData.packageToModule != null) { 172 packageToModule = ArchivedData.packageToModule; 173 } else { 174 packageToModule = new ConcurrentHashMap<>(1024); 175 ArchivedData.packageToModule = packageToModule; 176 } 177 } 178 179 // maps a module name to a module reference 180 private final Map<String, ModuleReference> nameToModule; 181 182 // maps a module reference to a module reader 183 private final Map<ModuleReference, ModuleReader> moduleToReader; 184 185 // cache of resource name -> list of URLs. 186 // used only for resources that are not in module packages 187 private volatile SoftReference<Map<String, List<URL>>> resourceCache; 188 189 /** 190 * Create a new instance. 191 */ 192 BuiltinClassLoader(String name, BuiltinClassLoader parent, URLClassPath ucp) { 193 // ensure getParent() returns null when the parent is the boot loader 194 super(name, parent == null || parent == ClassLoaders.bootLoader() ? null : parent); 195 196 this.parent = parent; 197 this.ucp = ucp; 198 199 this.nameToModule = new ConcurrentHashMap<>(32); 200 this.moduleToReader = new ConcurrentHashMap<>(); 201 } 202 203 /** 204 * Returns {@code true} if there is a class path associated with this 205 * class loader. 206 */ 207 boolean hasClassPath() { 208 return ucp != null; 209 } 210 211 /** 212 * Register a module this class loader. This has the effect of making the 213 * types in the module visible. 214 */ 215 public void loadModule(ModuleReference mref) { 216 ModuleDescriptor descriptor = mref.descriptor(); 217 String mn = descriptor.name(); 218 if (nameToModule.putIfAbsent(mn, mref) != null) { 219 throw new InternalError(mn + " already defined to this loader"); 220 } 221 222 LoadedModule loadedModule = new LoadedModule(this, mref); 223 for (String pn : descriptor.packages()) { 224 LoadedModule other = packageToModule.putIfAbsent(pn, loadedModule); 225 if (other != null) { 226 throw new InternalError(pn + " in modules " + mn + " and " 227 + other.name()); 228 } 229 } 230 231 // clear resources cache if VM is already initialized 232 if (resourceCache != null && VM.isModuleSystemInited()) { 233 resourceCache = null; 234 } 235 } 236 237 /** 238 * Returns the {@code ModuleReference} for the named module defined to 239 * this class loader; or {@code null} if not defined. 240 * 241 * @param name The name of the module to find 242 */ 243 protected ModuleReference findModule(String name) { 244 return nameToModule.get(name); 245 } 246 247 248 // -- finding resources 249 250 /** 251 * Returns a URL to a resource of the given name in a module defined to 252 * this class loader. 253 */ 254 @Override 255 public URL findResource(String mn, String name) throws IOException { 256 URL url = null; 257 258 if (mn != null) { 259 // find in module 260 ModuleReference mref = nameToModule.get(mn); 261 if (mref != null) { 262 url = findResource(mref, name); 263 } 264 } else { 265 // find on class path 266 url = findResourceOnClassPath(name); 267 } 268 269 return checkURL(url); // check access before returning 270 } 271 272 /** 273 * Returns an input stream to a resource of the given name in a module 274 * defined to this class loader. 275 */ 276 public InputStream findResourceAsStream(String mn, String name) 277 throws IOException 278 { 279 // Need URL to resource when running with a security manager so that 280 // the right permission check is done. 281 if (System.getSecurityManager() != null || mn == null) { 282 URL url = findResource(mn, name); 283 return (url != null) ? url.openStream() : null; 284 } 285 286 // find in module defined to this loader, no security manager 287 ModuleReference mref = nameToModule.get(mn); 288 if (mref != null) { 289 return moduleReaderFor(mref).open(name).orElse(null); 290 } else { 291 return null; 292 } 293 } 294 295 /** 296 * Finds a resource with the given name in the modules defined to this 297 * class loader or its class path. 298 */ 299 @Override 300 public URL findResource(String name) { 301 String pn = Resources.toPackageName(name); 302 LoadedModule module = packageToModule.get(pn); 303 if (module != null) { 304 305 // resource is in a package of a module defined to this loader 306 if (module.loader() == this) { 307 URL url; 308 try { 309 url = findResource(module.name(), name); // checks URL 310 } catch (IOException ioe) { 311 return null; 312 } 313 if (url != null 314 && (name.endsWith(".class") 315 || url.toString().endsWith("/") 316 || isOpen(module.mref(), pn))) { 317 return url; 318 } 319 } 320 321 } else { 322 323 // not in a module package but may be in module defined to this loader 324 try { 325 List<URL> urls = findMiscResource(name); 326 if (!urls.isEmpty()) { 327 URL url = urls.get(0); 328 if (url != null) { 329 return checkURL(url); // check access before returning 330 } 331 } 332 } catch (IOException ioe) { 333 return null; 334 } 335 336 } 337 338 // search class path 339 URL url = findResourceOnClassPath(name); 340 return checkURL(url); 341 } 342 343 /** 344 * Returns an enumeration of URL objects to all the resources with the 345 * given name in modules defined to this class loader or on the class 346 * path of this loader. 347 */ 348 @Override 349 public Enumeration<URL> findResources(String name) throws IOException { 350 List<URL> checked = new ArrayList<>(); // list of checked URLs 351 352 String pn = Resources.toPackageName(name); 353 LoadedModule module = packageToModule.get(pn); 354 if (module != null) { 355 356 // resource is in a package of a module defined to this loader 357 if (module.loader() == this) { 358 URL url = findResource(module.name(), name); // checks URL 359 if (url != null 360 && (name.endsWith(".class") 361 || url.toString().endsWith("/") 362 || isOpen(module.mref(), pn))) { 363 checked.add(url); 364 } 365 } 366 367 } else { 368 // not in a package of a module defined to this loader 369 for (URL url : findMiscResource(name)) { 370 url = checkURL(url); 371 if (url != null) { 372 checked.add(url); 373 } 374 } 375 } 376 377 // class path (not checked) 378 Enumeration<URL> e = findResourcesOnClassPath(name); 379 380 // concat the checked URLs and the (not checked) class path 381 return new Enumeration<>() { 382 final Iterator<URL> iterator = checked.iterator(); 383 URL next; 384 private boolean hasNext() { 385 if (next != null) { 386 return true; 387 } else if (iterator.hasNext()) { 388 next = iterator.next(); 389 return true; 390 } else { 391 // need to check each URL 392 while (e.hasMoreElements() && next == null) { 393 next = checkURL(e.nextElement()); 394 } 395 return next != null; 396 } 397 } 398 @Override 399 public boolean hasMoreElements() { 400 return hasNext(); 401 } 402 @Override 403 public URL nextElement() { 404 if (hasNext()) { 405 URL result = next; 406 next = null; 407 return result; 408 } else { 409 throw new NoSuchElementException(); 410 } 411 } 412 }; 413 414 } 415 416 /** 417 * Returns the list of URLs to a "miscellaneous" resource in modules 418 * defined to this loader. A miscellaneous resource is not in a module 419 * package, e.g. META-INF/services/p.S. 420 * 421 * The cache used by this method avoids repeated searching of all modules. 422 */ 423 private List<URL> findMiscResource(String name) throws IOException { 424 SoftReference<Map<String, List<URL>>> ref = this.resourceCache; 425 Map<String, List<URL>> map = (ref != null) ? ref.get() : null; 426 if (map == null) { 427 // only cache resources after VM is fully initialized 428 if (VM.isModuleSystemInited()) { 429 map = new ConcurrentHashMap<>(); 430 this.resourceCache = new SoftReference<>(map); 431 } 432 } else { 433 List<URL> urls = map.get(name); 434 if (urls != null) 435 return urls; 436 } 437 438 // search all modules for the resource 439 List<URL> urls; 440 try { 441 urls = AccessController.doPrivileged( 442 new PrivilegedExceptionAction<>() { 443 @Override 444 public List<URL> run() throws IOException { 445 List<URL> result = null; 446 for (ModuleReference mref : nameToModule.values()) { 447 URI u = moduleReaderFor(mref).find(name).orElse(null); 448 if (u != null) { 449 try { 450 if (result == null) 451 result = new ArrayList<>(); 452 result.add(u.toURL()); 453 } catch (MalformedURLException | 454 IllegalArgumentException e) { 455 } 456 } 457 } 458 return (result != null) ? result : Collections.emptyList(); 459 } 460 }); 461 } catch (PrivilegedActionException pae) { 462 throw (IOException) pae.getCause(); 463 } 464 465 // only cache resources after VM is fully initialized 466 if (map != null) { 467 map.putIfAbsent(name, urls); 468 } 469 470 return urls; 471 } 472 473 /** 474 * Returns the URL to a resource in a module or {@code null} if not found. 475 */ 476 private URL findResource(ModuleReference mref, String name) throws IOException { 477 URI u; 478 if (System.getSecurityManager() == null) { 479 u = moduleReaderFor(mref).find(name).orElse(null); 480 } else { 481 try { 482 u = AccessController.doPrivileged(new PrivilegedExceptionAction<> () { 483 @Override 484 public URI run() throws IOException { 485 return moduleReaderFor(mref).find(name).orElse(null); 486 } 487 }); 488 } catch (PrivilegedActionException pae) { 489 throw (IOException) pae.getCause(); 490 } 491 } 492 if (u != null) { 493 try { 494 return u.toURL(); 495 } catch (MalformedURLException | IllegalArgumentException e) { } 496 } 497 return null; 498 } 499 500 /** 501 * Returns the URL to a resource in a module. Returns {@code null} if not found 502 * or an I/O error occurs. 503 */ 504 private URL findResourceOrNull(ModuleReference mref, String name) { 505 try { 506 return findResource(mref, name); 507 } catch (IOException ignore) { 508 return null; 509 } 510 } 511 512 /** 513 * Returns a URL to a resource on the class path. 514 */ 515 private URL findResourceOnClassPath(String name) { 516 if (hasClassPath()) { 517 if (System.getSecurityManager() == null) { 518 return ucp.findResource(name, false); 519 } else { 520 PrivilegedAction<URL> pa = () -> ucp.findResource(name, false); 521 return AccessController.doPrivileged(pa); 522 } 523 } else { 524 // no class path 525 return null; 526 } 527 } 528 529 /** 530 * Returns the URLs of all resources of the given name on the class path. 531 */ 532 private Enumeration<URL> findResourcesOnClassPath(String name) { 533 if (hasClassPath()) { 534 if (System.getSecurityManager() == null) { 535 return ucp.findResources(name, false); 536 } else { 537 PrivilegedAction<Enumeration<URL>> pa; 538 pa = () -> ucp.findResources(name, false); 539 return AccessController.doPrivileged(pa); 540 } 541 } else { 542 // no class path 543 return Collections.emptyEnumeration(); 544 } 545 } 546 547 // -- finding/loading classes 548 549 /** 550 * Finds the class with the specified binary name. 551 */ 552 @Override 553 protected Class<?> findClass(String cn) throws ClassNotFoundException { 554 // no class loading until VM is fully initialized 555 if (!VM.isModuleSystemInited()) 556 throw new ClassNotFoundException(cn); 557 558 // find the candidate module for this class 559 LoadedModule loadedModule = findLoadedModule(cn); 560 561 Class<?> c = null; 562 if (loadedModule != null) { 563 564 // attempt to load class in module defined to this loader 565 if (loadedModule.loader() == this) { 566 c = findClassInModuleOrNull(loadedModule, cn); 567 } 568 569 } else { 570 571 // search class path 572 if (hasClassPath()) { 573 c = findClassOnClassPathOrNull(cn); 574 } 575 576 } 577 578 // not found 579 if (c == null) 580 throw new ClassNotFoundException(cn); 581 582 return c; 583 } 584 585 /** 586 * Finds the class with the specified binary name in a module. 587 * This method returns {@code null} if the class cannot be found 588 * or not defined in the specified module. 589 */ 590 @Override 591 protected Class<?> findClass(String mn, String cn) { 592 if (mn != null) { 593 // find the candidate module for this class 594 LoadedModule loadedModule = findLoadedModule(mn, cn); 595 if (loadedModule == null) { 596 return null; 597 } 598 599 // attempt to load class in module defined to this loader 600 assert loadedModule.loader() == this; 601 return findClassInModuleOrNull(loadedModule, cn); 602 } 603 604 // search class path 605 if (hasClassPath()) { 606 return findClassOnClassPathOrNull(cn); 607 } 608 609 return null; 610 } 611 612 /** 613 * Loads the class with the specified binary name. 614 */ 615 @Override 616 protected Class<?> loadClass(String cn, boolean resolve) 617 throws ClassNotFoundException 618 { 619 Class<?> c = loadClassOrNull(cn, resolve); 620 if (c == null) 621 throw new ClassNotFoundException(cn); 622 return c; 623 } 624 625 /** 626 * A variation of {@code loadClass} to load a class with the specified 627 * binary name. This method returns {@code null} when the class is not 628 * found. 629 */ 630 protected Class<?> loadClassOrNull(String cn, boolean resolve) { 631 synchronized (getClassLoadingLock(cn)) { 632 // check if already loaded 633 Class<?> c = findLoadedClass(cn); 634 635 if (c == null) { 636 637 // find the candidate module for this class 638 LoadedModule loadedModule = findLoadedModule(cn); 639 if (loadedModule != null) { 640 641 // package is in a module 642 BuiltinClassLoader loader = loadedModule.loader(); 643 if (loader == this) { 644 if (VM.isModuleSystemInited()) { 645 c = findClassInModuleOrNull(loadedModule, cn); 646 } 647 } else { 648 // delegate to the other loader 649 c = loader.loadClassOrNull(cn); 650 } 651 652 } else { 653 654 // check parent 655 if (parent != null) { 656 c = parent.loadClassOrNull(cn); 657 } 658 659 // check class path 660 if (c == null && hasClassPath() && VM.isModuleSystemInited()) { 661 c = findClassOnClassPathOrNull(cn); 662 } 663 } 664 665 } 666 667 if (resolve && c != null) 668 resolveClass(c); 669 670 return c; 671 } 672 } 673 674 /** 675 * A variation of {@code loadClass} to load a class with the specified 676 * binary name. This method returns {@code null} when the class is not 677 * found. 678 */ 679 protected final Class<?> loadClassOrNull(String cn) { 680 return loadClassOrNull(cn, false); 681 } 682 683 /** 684 * Finds the candidate loaded module for the given class name. 685 * Returns {@code null} if none of the modules defined to this 686 * class loader contain the API package for the class. 687 */ 688 private LoadedModule findLoadedModule(String cn) { 689 int pos = cn.lastIndexOf('.'); 690 if (pos < 0) 691 return null; // unnamed package 692 693 String pn = cn.substring(0, pos); 694 return packageToModule.get(pn); 695 } 696 697 /** 698 * Finds the candidate loaded module for the given class name 699 * in the named module. Returns {@code null} if the named module 700 * is not defined to this class loader or does not contain 701 * the API package for the class. 702 */ 703 private LoadedModule findLoadedModule(String mn, String cn) { 704 LoadedModule loadedModule = findLoadedModule(cn); 705 if (loadedModule != null && mn.equals(loadedModule.name())) { 706 return loadedModule; 707 } else { 708 return null; 709 } 710 } 711 712 /** 713 * Finds the class with the specified binary name if in a module 714 * defined to this ClassLoader. 715 * 716 * @return the resulting Class or {@code null} if not found 717 */ 718 private Class<?> findClassInModuleOrNull(LoadedModule loadedModule, String cn) { 719 if (System.getSecurityManager() == null) { 720 return defineClass(cn, loadedModule); 721 } else { 722 PrivilegedAction<Class<?>> pa = () -> defineClass(cn, loadedModule); 723 return AccessController.doPrivileged(pa); 724 } 725 } 726 727 /** 728 * Finds the class with the specified binary name on the class path. 729 * 730 * @return the resulting Class or {@code null} if not found 731 */ 732 private Class<?> findClassOnClassPathOrNull(String cn) { 733 String path = cn.replace('.', '/').concat(".class"); 734 if (System.getSecurityManager() == null) { 735 Resource res = ucp.getResource(path, false); 736 if (res != null) { 737 try { 738 return defineClass(cn, res); 739 } catch (IOException ioe) { 740 // TBD on how I/O errors should be propagated 741 } 742 } 743 return null; 744 } else { 745 // avoid use of lambda here 746 PrivilegedAction<Class<?>> pa = new PrivilegedAction<>() { 747 public Class<?> run() { 748 Resource res = ucp.getResource(path, false); 749 if (res != null) { 750 try { 751 return defineClass(cn, res); 752 } catch (IOException ioe) { 753 // TBD on how I/O errors should be propagated 754 } 755 } 756 return null; 757 } 758 }; 759 return AccessController.doPrivileged(pa); 760 } 761 } 762 763 /** 764 * Defines the given binary class name to the VM, loading the class 765 * bytes from the given module. 766 * 767 * @return the resulting Class or {@code null} if an I/O error occurs 768 */ 769 private Class<?> defineClass(String cn, LoadedModule loadedModule) { 770 ModuleReference mref = loadedModule.mref(); 771 ModuleReader reader = moduleReaderFor(mref); 772 773 try { 774 ByteBuffer bb = null; 775 URL csURL = null; 776 777 // locate class file, special handling for patched modules to 778 // avoid locating the resource twice 779 String rn = cn.replace('.', '/').concat(".class"); 780 if (reader instanceof PatchedModuleReader) { 781 Resource r = ((PatchedModuleReader)reader).findResource(rn); 782 if (r != null) { 783 bb = r.getByteBuffer(); 784 csURL = r.getCodeSourceURL(); 785 } 786 } else { 787 bb = reader.read(rn).orElse(null); 788 csURL = loadedModule.codeSourceURL(); 789 } 790 791 if (bb == null) { 792 // class not found 793 return null; 794 } 795 796 CodeSource cs = new CodeSource(csURL, (CodeSigner[]) null); 797 try { 798 // define class to VM 799 return defineClass(cn, bb, cs); 800 801 } finally { 802 reader.release(bb); 803 } 804 805 } catch (IOException ioe) { 806 // TBD on how I/O errors should be propagated 807 return null; 808 } 809 } 810 811 /** 812 * Defines the given binary class name to the VM, loading the class 813 * bytes via the given Resource object. 814 * 815 * @return the resulting Class 816 * @throws IOException if reading the resource fails 817 * @throws SecurityException if there is a sealing violation (JAR spec) 818 */ 819 private Class<?> defineClass(String cn, Resource res) throws IOException { 820 URL url = res.getCodeSourceURL(); 821 822 // if class is in a named package then ensure that the package is defined 823 int pos = cn.lastIndexOf('.'); 824 if (pos != -1) { 825 String pn = cn.substring(0, pos); 826 Manifest man = res.getManifest(); 827 defineOrCheckPackage(pn, man, url); 828 } 829 830 // defines the class to the runtime 831 ByteBuffer bb = res.getByteBuffer(); 832 if (bb != null) { 833 CodeSigner[] signers = res.getCodeSigners(); 834 CodeSource cs = new CodeSource(url, signers); 835 return defineClass(cn, bb, cs); 836 } else { 837 byte[] b = res.getBytes(); 838 CodeSigner[] signers = res.getCodeSigners(); 839 CodeSource cs = new CodeSource(url, signers); 840 return defineClass(cn, b, 0, b.length, cs); 841 } 842 } 843 844 845 // -- packages 846 847 /** 848 * Defines a package in this ClassLoader. If the package is already defined 849 * then its sealing needs to be checked if sealed by the legacy sealing 850 * mechanism. 851 * 852 * @throws SecurityException if there is a sealing violation (JAR spec) 853 */ 854 protected Package defineOrCheckPackage(String pn, Manifest man, URL url) { 855 Package pkg = getAndVerifyPackage(pn, man, url); 856 if (pkg == null) { 857 try { 858 if (man != null) { 859 pkg = definePackage(pn, man, url); 860 } else { 861 pkg = definePackage(pn, null, null, null, null, null, null, null); 862 } 863 } catch (IllegalArgumentException iae) { 864 // defined by another thread so need to re-verify 865 pkg = getAndVerifyPackage(pn, man, url); 866 if (pkg == null) 867 throw new InternalError("Cannot find package: " + pn); 868 } 869 } 870 return pkg; 871 } 872 873 /** 874 * Gets the Package with the specified package name. If defined 875 * then verifies it against the manifest and code source. 876 * 877 * @throws SecurityException if there is a sealing violation (JAR spec) 878 */ 879 private Package getAndVerifyPackage(String pn, Manifest man, URL url) { 880 Package pkg = getDefinedPackage(pn); 881 if (pkg != null) { 882 if (pkg.isSealed()) { 883 if (!pkg.isSealed(url)) { 884 throw new SecurityException( 885 "sealing violation: package " + pn + " is sealed"); 886 } 887 } else { 888 // can't seal package if already defined without sealing 889 if ((man != null) && isSealed(pn, man)) { 890 throw new SecurityException( 891 "sealing violation: can't seal package " + pn + 892 ": already defined"); 893 } 894 } 895 } 896 return pkg; 897 } 898 899 /** 900 * Defines a new package in this ClassLoader. The attributes in the specified 901 * Manifest are used to get the package version and sealing information. 902 * 903 * @throws IllegalArgumentException if the package name duplicates an 904 * existing package either in this class loader or one of its ancestors 905 * @throws SecurityException if the package name is untrusted in the manifest 906 */ 907 private Package definePackage(String pn, Manifest man, URL url) { 908 String specTitle = null; 909 String specVersion = null; 910 String specVendor = null; 911 String implTitle = null; 912 String implVersion = null; 913 String implVendor = null; 914 String sealed = null; 915 URL sealBase = null; 916 917 if (man != null) { 918 Attributes attr = SharedSecrets.javaUtilJarAccess() 919 .getTrustedAttributes(man, pn.replace('.', '/').concat("/")); 920 if (attr != null) { 921 specTitle = attr.getValue(Attributes.Name.SPECIFICATION_TITLE); 922 specVersion = attr.getValue(Attributes.Name.SPECIFICATION_VERSION); 923 specVendor = attr.getValue(Attributes.Name.SPECIFICATION_VENDOR); 924 implTitle = attr.getValue(Attributes.Name.IMPLEMENTATION_TITLE); 925 implVersion = attr.getValue(Attributes.Name.IMPLEMENTATION_VERSION); 926 implVendor = attr.getValue(Attributes.Name.IMPLEMENTATION_VENDOR); 927 sealed = attr.getValue(Attributes.Name.SEALED); 928 } 929 930 attr = man.getMainAttributes(); 931 if (attr != null) { 932 if (specTitle == null) 933 specTitle = attr.getValue(Attributes.Name.SPECIFICATION_TITLE); 934 if (specVersion == null) 935 specVersion = attr.getValue(Attributes.Name.SPECIFICATION_VERSION); 936 if (specVendor == null) 937 specVendor = attr.getValue(Attributes.Name.SPECIFICATION_VENDOR); 938 if (implTitle == null) 939 implTitle = attr.getValue(Attributes.Name.IMPLEMENTATION_TITLE); 940 if (implVersion == null) 941 implVersion = attr.getValue(Attributes.Name.IMPLEMENTATION_VERSION); 942 if (implVendor == null) 943 implVendor = attr.getValue(Attributes.Name.IMPLEMENTATION_VENDOR); 944 if (sealed == null) 945 sealed = attr.getValue(Attributes.Name.SEALED); 946 } 947 948 // package is sealed 949 if ("true".equalsIgnoreCase(sealed)) 950 sealBase = url; 951 } 952 return definePackage(pn, 953 specTitle, 954 specVersion, 955 specVendor, 956 implTitle, 957 implVersion, 958 implVendor, 959 sealBase); 960 } 961 962 /** 963 * Returns {@code true} if the specified package name is sealed according to 964 * the given manifest. 965 * 966 * @throws SecurityException if the package name is untrusted in the manifest 967 */ 968 private boolean isSealed(String pn, Manifest man) { 969 Attributes attr = SharedSecrets.javaUtilJarAccess() 970 .getTrustedAttributes(man, pn.replace('.', '/').concat("/")); 971 String sealed = null; 972 if (attr != null) 973 sealed = attr.getValue(Attributes.Name.SEALED); 974 if (sealed == null && (attr = man.getMainAttributes()) != null) 975 sealed = attr.getValue(Attributes.Name.SEALED); 976 return "true".equalsIgnoreCase(sealed); 977 } 978 979 // -- permissions 980 981 /** 982 * Returns the permissions for the given CodeSource. 983 */ 984 @Override 985 protected PermissionCollection getPermissions(CodeSource cs) { 986 return new LazyCodeSourcePermissionCollection(super.getPermissions(cs), cs); 987 } 988 989 // -- miscellaneous supporting methods 990 991 /** 992 * Returns the ModuleReader for the given module, creating it if needed. 993 */ 994 private ModuleReader moduleReaderFor(ModuleReference mref) { 995 ModuleReader reader = moduleToReader.get(mref); 996 if (reader == null) { 997 // avoid method reference during startup 998 Function<ModuleReference, ModuleReader> create = new Function<>() { 999 public ModuleReader apply(ModuleReference moduleReference) { 1000 try { 1001 return mref.open(); 1002 } catch (IOException e) { 1003 // Return a null module reader to avoid a future class 1004 // load attempting to open the module again. 1005 return new NullModuleReader(); 1006 } 1007 } 1008 }; 1009 reader = moduleToReader.computeIfAbsent(mref, create); 1010 } 1011 return reader; 1012 } 1013 1014 /** 1015 * A ModuleReader that doesn't read any resources. 1016 */ 1017 private static class NullModuleReader implements ModuleReader { 1018 @Override 1019 public Optional<URI> find(String name) { 1020 return Optional.empty(); 1021 } 1022 @Override 1023 public Stream<String> list() { 1024 return Stream.empty(); 1025 } 1026 @Override 1027 public void close() { 1028 throw new InternalError("Should not get here"); 1029 } 1030 }; 1031 1032 /** 1033 * Returns true if the given module opens the given package 1034 * unconditionally. 1035 * 1036 * @implNote This method currently iterates over each of the open 1037 * packages. This will be replaced once the ModuleDescriptor.Opens 1038 * API is updated. 1039 */ 1040 private boolean isOpen(ModuleReference mref, String pn) { 1041 ModuleDescriptor descriptor = mref.descriptor(); 1042 if (descriptor.isOpen() || descriptor.isAutomatic()) 1043 return true; 1044 for (ModuleDescriptor.Opens opens : descriptor.opens()) { 1045 String source = opens.source(); 1046 if (!opens.isQualified() && source.equals(pn)) { 1047 return true; 1048 } 1049 } 1050 return false; 1051 } 1052 1053 /** 1054 * Checks access to the given URL. We use URLClassPath for consistent 1055 * checking with java.net.URLClassLoader. 1056 */ 1057 private static URL checkURL(URL url) { 1058 return URLClassPath.checkURL(url); 1059 } 1060 1061 // Called from VM only, during -Xshare:dump 1062 private void resetArchivedStates() { 1063 ucp = null; 1064 } 1065 }