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