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 compatibility with other agents #7916

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ private static void installBytebuddyAgent(
.with(AgentBuilder.DescriptionStrategy.Default.POOL_ONLY)
.with(AgentTooling.poolStrategy())
.with(new ClassLoadListener())
.with(AgentTooling.transformListener())
.with(AgentTooling.locationStrategy());
if (JavaModule.isSupported()) {
agentBuilder = agentBuilder.with(new ExposeAgentBootstrapListener(inst));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,15 @@ public TypePool.Resolution find(String className) {
if (OBJECT_NAME.equals(className)) {
return OBJECT_RESOLUTION;
}
// Skip cache for the type that is currently being transformed.
// If class has been transformed by another agent or by class loader it is possible that the
// cached TypeDescription isn't the same as the one built from the actual bytes that are
// being defined. For example if another agent adds an interface to the class then returning
// the cached description that does not have that interface would result in bytebuddy removing
// that interface.
if (AgentTooling.isTransforming(loaderRef != null ? loaderRef.get() : null, className)) {
return null;
}

TypePool.Resolution existingResolution =
sharedResolutionCache.get(new TypeCacheKey(loaderHash, loaderRef, className));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import java.util.Iterator;
import java.util.ServiceLoader;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.utility.JavaModule;

/**
* This class contains class references for objects shared by the agent installer as well as muzzle
Expand All @@ -22,6 +23,8 @@ public final class AgentTooling {
private static final AgentBuilder.PoolStrategy POOL_STRATEGY =
new AgentCachingPoolStrategy(LOCATION_STRATEGY);

private static final ThreadLocal<CurrentTransform> CURRENT_TRANSFORM = new ThreadLocal<>();

public static AgentLocationStrategy locationStrategy() {
return LOCATION_STRATEGY;
}
Expand All @@ -30,6 +33,10 @@ public static AgentBuilder.PoolStrategy poolStrategy() {
return POOL_STRATEGY;
}

public static AgentBuilder.Listener transformListener() {
return new ClassTransformListener();
}

private static ClassLoader getBootstrapProxy() {
Iterator<BootstrapProxyProvider> iterator =
ServiceLoader.load(BootstrapProxyProvider.class, AgentTooling.class.getClassLoader())
Expand All @@ -42,5 +49,42 @@ private static ClassLoader getBootstrapProxy() {
return null;
}

public static boolean isTransforming(ClassLoader classLoader, String className) {
CurrentTransform currentTransform = CURRENT_TRANSFORM.get();
if (currentTransform == null) {
return false;
}
return currentTransform.className.equals(className)
&& currentTransform.classLoader == classLoader;
}

public static void completeLoadClass() {
CURRENT_TRANSFORM.remove();
}

laurit marked this conversation as resolved.
Show resolved Hide resolved
private static class ClassTransformListener extends AgentBuilder.Listener.Adapter {
@Override
public void onDiscovery(
String typeName, ClassLoader classLoader, JavaModule module, boolean loaded) {
CURRENT_TRANSFORM.set(new CurrentTransform(classLoader, typeName));
}

@Override
public void onComplete(
String typeName, ClassLoader classLoader, JavaModule module, boolean loaded) {
CURRENT_TRANSFORM.remove();
}
}

private static class CurrentTransform {
private final ClassLoader classLoader;
private final String className;

CurrentTransform(ClassLoader classLoader, String className) {
this.classLoader = classLoader;
this.className = className;
}
}

private AgentTooling() {}
}