JDK-8349545 : ClassLoader.definePackage() throws IllegalArgumentException if package already defined
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang:class_loading
  • Affected Version: 21,23
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • Submitted: 2025-02-06
  • Updated: 2025-02-23
Related Reports
CSR :  
Relates :  
Relates :  
Relates :  
Description
j.l.ClassLoader.definePackage() contains the following check, which triggers IAEs when classes from the same package are loaded against the same class loader.
{code}
if (packages.putIfAbsent(name, p) != null)
  throw new IllegalArgumentException(name);
{code}

This can happen relatively easy with Weld's {{org.jboss.weld.bootstrap.ConcurrentBeanDeployer}} ([code on GitHub|https://github.com/weld/core/blob/master/impl/src/main/java/org/jboss/weld/bootstrap/ConcurrentBeanDeployer.java]).

The issue has also been reported to [Quarkus|https://github.com/quarkusio/quarkus/issues/37363].

Concurrent class loading against the same class loader and package seems legit. It looks like it can happen in every code base at any time.

The other two ConcurrentHashMaps in ClassLoader, package2certs and parallelLockMap, are not affected by this issue.

The package2cert.putIfAbsent() in checkCerts() is fine, as it only throws if the concurrently added array of certificates is different.

definePackage() could use a similar approach and replace the above code snippet with something like this:
{code}
Package ex = packages.putIfAbsent(name, p);
if (ex == null)
  return p;
if (!ex.equals(p))
  throw new IllegalArgumentException(name);
return ex;
{code}
and probably also enhancing the exception message.

j.l.Package however doesn't have equals/hashCode implementation, so those would have to be added as well. The problematic piece is likely to avoid the "nasty side effects" of a call to URL.equals() (the potential call to InetAddress.getByName).

When and whether the issue happens depends on the application and the performance of the system - the more cores, the higher the probability to hit this IAE.
Comments
A pull request was submitted for review. Branch: master URL: https://git.openjdk.org/jdk/pull/23737 Date: 2025-02-23 11:32:41 +0000
23-02-2025

I'm not that familiar w/ the PR/review process in the OpenJDK project, so I've created that PR as a "draft PR" for now, because I'm unsure about whether the sealed-checks should be moved up to CL.
23-02-2025

Took a stab on this one in https://github.com/openjdk/jdk/pull/23737
23-02-2025

Package is a legacy API from JDK 1.2 (1998). Many of its flaw/issues were deal with in JDK 9. The issue reported here with concurrent calls to definePackage to define the same package has come up a few times over the years. The built-in class loaders, URLClassLoader, and a few others in the JDK handle the IAE and checking for sealing violations. What is being asked here is for ClassLoader.definePackage itself to be changed to avoid custom class loaders needing to deal with it.
14-02-2025