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     }
1088 }