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