Skip to content

Commit b566e30

Browse files
authored
fix: prevent Lazy TypePool from drifting after type resolution (#1857)
A Lazy TypePool was mutating during type resolution, causing its configuration to deviate from the initial state. This commit ensures the TypePool retains its original configuration by freezing the base state before resolution and isolating resolved types in a temporary context.
1 parent 0799655 commit b566e30

File tree

3 files changed

+90
-4
lines changed

3 files changed

+90
-4
lines changed

byte-buddy-dep/src/main/java/net/bytebuddy/pool/TypePool.java

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,66 @@ public void clear() {
406406
}
407407
}
408408

409+
/**
410+
* A cache provider wrapper that avoids caching illegal resolutions so that future lookups can be reattempted.
411+
*/
412+
@HashCodeAndEqualsPlugin.Enhance
413+
class WithIllegalResolutionReattempt implements CacheProvider {
414+
415+
/**
416+
* The delegated cache provider.
417+
*/
418+
private final CacheProvider delegate;
419+
420+
/**
421+
* Creates a new cache provider that suppresses caching of illegal resolutions.
422+
*
423+
* @param delegate The cache provider to delegate to.
424+
*/
425+
public WithIllegalResolutionReattempt(CacheProvider delegate) {
426+
this.delegate = delegate;
427+
}
428+
429+
/**
430+
* Returns a cache provider that suppresses caching of illegal resolutions without wrapping twice.
431+
*
432+
* @param cacheProvider The cache provider to potentially wrap.
433+
* @return A cache provider that does not store illegal resolutions.
434+
*/
435+
public static CacheProvider of(CacheProvider cacheProvider) {
436+
return cacheProvider instanceof WithIllegalResolutionReattempt
437+
? cacheProvider
438+
: new WithIllegalResolutionReattempt(cacheProvider);
439+
}
440+
441+
/**
442+
* {@inheritDoc}
443+
*/
444+
@MaybeNull
445+
public Resolution find(String name) {
446+
Resolution resolution = delegate.find(name);
447+
return resolution != null && !resolution.isResolved()
448+
? UNRESOLVED
449+
: resolution;
450+
}
451+
452+
/**
453+
* {@inheritDoc}
454+
*/
455+
public Resolution register(String name, Resolution resolution) {
456+
return resolution.isResolved()
457+
? delegate.register(name, resolution)
458+
: resolution;
459+
}
460+
461+
/**
462+
* {@inheritDoc}
463+
*/
464+
public void clear() {
465+
delegate.clear();
466+
}
467+
}
468+
409469
/**
410470
* A discriminating cache provider that delegates a type name to one of two caches.
411471
*/
@@ -1014,7 +1074,7 @@ public WithLazyResolution(CacheProvider cacheProvider, ClassFileLocator classFil
10141074
* @param lazinessMode The mode of lazy resolution.
10151075
*/
10161076
public WithLazyResolution(CacheProvider cacheProvider, ClassFileLocator classFileLocator, ReaderMode readerMode, LazinessMode lazinessMode) {
1017-
super(cacheProvider, classFileLocator, readerMode);
1077+
super(CacheProvider.WithIllegalResolutionReattempt.of(cacheProvider), classFileLocator, readerMode);
10181078
this.lazinessMode = lazinessMode;
10191079
}
10201080

@@ -1028,7 +1088,7 @@ public WithLazyResolution(CacheProvider cacheProvider, ClassFileLocator classFil
10281088
* @param lazinessMode The mode of lazy resolution.
10291089
*/
10301090
public WithLazyResolution(CacheProvider cacheProvider, ClassFileLocator classFileLocator, ReaderMode readerMode, TypePool parentPool, LazinessMode lazinessMode) {
1031-
super(cacheProvider, classFileLocator, readerMode, parentPool);
1091+
super(CacheProvider.WithIllegalResolutionReattempt.of(cacheProvider), classFileLocator, readerMode, parentPool);
10321092
this.lazinessMode = lazinessMode;
10331093
}
10341094

@@ -1042,7 +1102,7 @@ public WithLazyResolution(CacheProvider cacheProvider, ClassFileLocator classFil
10421102
* @param lazinessMode The mode of lazy resolution.
10431103
*/
10441104
public WithLazyResolution(CacheProvider cacheProvider, ClassFileLocator classFileLocator, ReaderMode readerMode, AsmClassReader.Factory classReaderFactory, LazinessMode lazinessMode) {
1045-
super(cacheProvider, classFileLocator, readerMode, classReaderFactory);
1105+
super(CacheProvider.WithIllegalResolutionReattempt.of(cacheProvider), classFileLocator, readerMode, classReaderFactory);
10461106
this.lazinessMode = lazinessMode;
10471107
}
10481108

@@ -1057,7 +1117,7 @@ public WithLazyResolution(CacheProvider cacheProvider, ClassFileLocator classFil
10571117
* @param lazinessMode The mode of lazy resolution.
10581118
*/
10591119
public WithLazyResolution(CacheProvider cacheProvider, ClassFileLocator classFileLocator, ReaderMode readerMode, AsmClassReader.Factory classReaderFactory, TypePool parentPool, LazinessMode lazinessMode) {
1060-
super(cacheProvider, classFileLocator, readerMode, classReaderFactory, parentPool);
1120+
super(CacheProvider.WithIllegalResolutionReattempt.of(cacheProvider), classFileLocator, readerMode, classReaderFactory, parentPool);
10611121
this.lazinessMode = lazinessMode;
10621122
}
10631123

byte-buddy-dep/src/test/java/net/bytebuddy/pool/TypePoolCacheProviderTest.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package net.bytebuddy.pool;
22

3+
import net.bytebuddy.description.type.TypeDescription;
34
import net.bytebuddy.matcher.ElementMatchers;
45
import org.junit.Rule;
56
import org.junit.Test;
@@ -82,6 +83,18 @@ public void testDiscriminatingMatched() throws Exception {
8283
verify(unmatched).clear();
8384
}
8485

86+
@Test
87+
public void testWithIllegalResolutionReattempt() throws Exception {
88+
TypePool.CacheProvider cacheProvider = TypePool.CacheProvider.WithIllegalResolutionReattempt.of(new TypePool.CacheProvider.Simple());
89+
TypePool.Resolution illegal = new TypePool.Resolution.Illegal(FOO);
90+
assertThat(cacheProvider.register(FOO, illegal), sameInstance(illegal));
91+
assertThat(cacheProvider.find(FOO), nullValue(TypePool.Resolution.class));
92+
TypePool.Resolution legal = new TypePool.Resolution.Simple(TypeDescription.ForLoadedType.of(Object.class));
93+
assertThat(cacheProvider.register(FOO, legal), sameInstance(legal));
94+
assertThat(cacheProvider.find(FOO), sameInstance(legal));
95+
assertThat(TypePool.CacheProvider.WithIllegalResolutionReattempt.of(cacheProvider), sameInstance(cacheProvider));
96+
}
97+
8598
@Test
8699
public void testDiscriminatingUnmatched() throws Exception {
87100
TypePool.CacheProvider matched = mock(TypePool.CacheProvider.class), unmatched = mock(TypePool.CacheProvider.class);

byte-buddy-dep/src/test/java/net/bytebuddy/pool/TypePoolDefaultWithLazyResolutionTypeDescriptionTest.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,19 @@ protected TypeDescription.Generic describeInterfaceType(Class<?> type, int index
7777
return describe(type).getInterfaces().get(index);
7878
}
7979

80+
@Test
81+
public void testIllegalResolutionDoesNotPersist() throws Exception {
82+
TypePool typePool = new TypePool.Default.WithLazyResolution(new TypePool.CacheProvider.Simple(),
83+
ClassFileLocator.NoOp.INSTANCE,
84+
TypePool.Default.ReaderMode.FAST,
85+
lazinessMode);
86+
String name = "foo.Bar";
87+
TypePool.Resolution resolution = typePool.describe(name);
88+
assertThat(resolution.resolve().getName(), CoreMatchers.is(name));
89+
assertThat(resolution.isResolved(), CoreMatchers.is(false));
90+
assertThat(typePool.describe(name).resolve().getName(), CoreMatchers.is(name));
91+
}
92+
8093
@Test
8194
public void testTypeIsLazy() throws Exception {
8295
ClassFileLocator classFileLocator = spy(ClassFileLocator.ForClassLoader.ofSystemLoader());

0 commit comments

Comments
 (0)