Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve diagnostics for CGLIB ClassLoader issues with shared classes in parent ClassLoader #25940

Closed
iherasymenko opened this issue Oct 20, 2020 · 3 comments
Assignees
Labels
in: core Issues in core modules (aop, beans, core, context, expression) status: backported An issue that has been backported to maintenance branches type: enhancement A general enhancement
Milestone

Comments

@iherasymenko
Copy link

iherasymenko commented Oct 20, 2020

Reproducible on JDK 11, 15 (presumably 9+) and the latest Spring Framework (5.2.9).

I put together a simple reproducer, which mimics the Tomcat setup where this issue can be observed.

The deployment configuration is as follows.

-- lib
     - spring libraries
     - shared lib
-- webapp1
     - Configuration1.class that references a class with @Transactional annotation from the shared lib
-- webapp2
     - Configuration2.class that references a class with @Transactional annotation from the shared lib
  • If the JVM is run with --illegal-access=deny and BOTH apps are deployed, the second app fails with the error.
  • If the JVM is run with --illegal-access=deny and just ONE app is deployed, everything works fine.
  • If the JVM is run with --illegal-access=warn (or simply without this argument) and either one app or both apps are deployed, everything works fine.
  • If the JVM is run without specifying --illegal-access, but the libraries are placed on the module path, the second app fails with the error.

The reproducer is here. Run gradlew runWithIllegalAccessDeny, gradlew runWithIllegalAccessWarn, and gradlew runOnModulePath accordingly.

The error:

java.lang.LinkageError-->loader 'app' attempted duplicate class definition for com.example.SimpleService$$EnhancerBySpringCGLIB$$df04dc18. (com.example.SimpleService$$EnhancerBySpringCGLIB$$df04dc18 is in unnamed module of loader 'app')

	at org.springframework.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:558)
	at org.springframework.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:363)
	at org.springframework.cglib.proxy.Enhancer.generate(Enhancer.java:585)
	at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:110)
	at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:108)
	at org.springframework.cglib.core.internal.LoadingCache$2.call(LoadingCache.java:54)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at org.springframework.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:61)
	at org.springframework.cglib.core.internal.LoadingCache.get(LoadingCache.java:34)
	at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:134)
	at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:319)
	at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:572)
	at org.springframework.cglib.proxy.Enhancer.createClass(Enhancer.java:419)
	at org.springframework.aop.framework.ObjenesisCglibAopProxy.createProxyClassAndInstance(ObjenesisCglibAopProxy.java:57)
	at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:205)
	... 17 more

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Oct 20, 2020
@jhoeller jhoeller self-assigned this Oct 20, 2020
@jhoeller
Copy link
Contributor

I'm afraid this is expected since the official JDK 9 Lookup.defineClass API only allows for defining a new class in the same ClassLoader as the "context class" (the original user class in this case), whereas our old ClassLoader.defineClass approach allows us to define the new class in the specific application ClassLoader (but unfortunately isn't a public API and therefore unavailable if you're applying --illegal-access=deny).

From that perspective, your current deployment layout is generally not supported with --illegal-access=deny. You'll have to co-locate your classes in each local application class loader where we are allowed to define isolated proxy classes for them.

That said, we could at least provide some hints for such scenarios in our documentation... since this isn't obvious at all.

@jhoeller jhoeller changed the title Proxy classes cannot be registered if "--illegal-access=deny" is specified Proxy classes for shared classes cannot be registered if "--illegal-access=deny" is specified Oct 20, 2020
@jhoeller jhoeller added in: web Issues in web modules (web, webmvc, webflux, websocket) type: documentation A documentation task and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Oct 20, 2020
@jhoeller jhoeller added this to the 5.2.10 milestone Oct 20, 2020
@iherasymenko
Copy link
Author

@jhoeller thanks for such a quick reply. Using --illegal-access=warn is not a problem for us (yet), so we will stick with this option.

Let me ask a question, just out of my curiosity. What if proxy classes had unique names per application context? Wouldn't that solve the issue?

@jhoeller jhoeller modified the milestones: 5.2.10, 5.2.11, 5.x Backlog Oct 26, 2020
@jhoeller jhoeller modified the milestones: 5.x Backlog, 5.3.2 Nov 11, 2020
@jhoeller jhoeller modified the milestones: 5.3.2, 5.x Backlog Dec 7, 2020
@jhoeller jhoeller modified the milestones: 5.x Backlog, 5.3.5 Jan 23, 2021
@jhoeller jhoeller modified the milestones: 5.3.5, 5.3.6 Mar 15, 2021
@jhoeller jhoeller modified the milestones: 5.3.6, 5.3.7 Apr 12, 2021
@jhoeller jhoeller modified the milestones: 5.3.7, 5.3.8 May 5, 2021
@jhoeller jhoeller modified the milestones: 5.3.8, 5.3.9 Jun 4, 2021
@jhoeller jhoeller modified the milestones: 5.3.9, 5.3.10 Jul 7, 2021
@jhoeller jhoeller removed this from the 5.3.10 milestone Sep 13, 2021
@jhoeller jhoeller added this to the 5.x Backlog milestone Sep 13, 2021
@jhoeller jhoeller modified the milestones: 5.x, 6.0.x Nov 1, 2021
@sbrannen sbrannen changed the title Proxy classes for shared classes cannot be registered if "--illegal-access=deny" is specified CGLIB: proxy classes for shared classes cannot be registered if "--illegal-access=deny" is specified Feb 1, 2022
@jhoeller jhoeller modified the milestones: 6.0.x, 6.x Backlog Jan 11, 2023
@jhoeller
Copy link
Contributor

jhoeller commented Jul 11, 2023

It looks like we can address this along the lines of #28747, throwing a corresponding exception from ReflectUtils.defineClass where we add a specific exception message for how to solve this. We don't really have a good place in the general documentation where this could be easily found, so it seems necessary to catch and explain this on the spot.

As for proxy classes with unique names, that would only solve part of the problem since there would still be leaks from the higher ClassLoader to the shared ClassLoader in the runtime-generated classes. It's definitely preferable to isolate this into each specific application ClassLoader.

@jhoeller jhoeller modified the milestones: 6.x Backlog, 6.0.11 Jul 11, 2023
@jhoeller jhoeller added the for: backport-to-5.3.x Marks an issue as a candidate for backport to 5.3.x label Jul 11, 2023
@github-actions github-actions bot added status: backported An issue that has been backported to maintenance branches and removed for: backport-to-5.3.x Marks an issue as a candidate for backport to 5.3.x labels Jul 11, 2023
@jhoeller jhoeller changed the title CGLIB: proxy classes for shared classes cannot be registered if "--illegal-access=deny" is specified Improve diagnostics for CGLIB ClassLoader issues with shared classes in parent ClassLoader Jul 11, 2023
@jhoeller jhoeller added in: core Issues in core modules (aop, beans, core, context, expression) type: enhancement A general enhancement and removed type: documentation A documentation task in: web Issues in web modules (web, webmvc, webflux, websocket) labels Jul 11, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core Issues in core modules (aop, beans, core, context, expression) status: backported An issue that has been backported to maintenance branches type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

3 participants