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