Re: Is it possible to instrument Thread.currentThread()

182 views
Skip to first unread message
Message has been deleted

Rafael Winterhalter

unread,
Jan 2, 2021, 3:25:53 PM1/2/21
to mustafa sancar koyunlu, Byte Buddy
You can try changing the circularity lock. Currently, it checks thread local state which requires the method that you are instrumenting. As a result, you cause the stack overflow.

Generally, it's difficult to instrument methods that are that central, you might need to sacrifice the comfort of Byte Buddy and use something purer such as ASM to get where you want for it.

Am Sa., 2. Jan. 2021 um 17:25 Uhr schrieb mustafa sancar koyunlu <mustafa.san...@gmail.com>:
Hi everyone and Rafael, 

I had this project idea where I want to change how Threads work. 
Basically, I want to convert a multithreaded library to a single thread for the sake of having a deterministic run via just installing an agent(actually my idea is to how controlled randomization where a second run will behave exactly like the first).

This requires me to change the behavior of almost all the classes relates threads like Thread. start/currentThread/sleep , Object.notify/wait etc... 

I am a little bit inspired by https://github.com/vmlens/vmlens but trying to achieve something else. 

I wanted to give bytebuddy a try but I got stuck really at the beginning:

As a baby step, I am just trying to instrument `currentThread` where I want to log it and call the original `currentThread` without changing the behavior. 

```
public static Thread currentThread(@Origin(cache = false) Method m) throws Exception {
log(() -> "Thread.currentThread intercepted");
try {
//new Throwable().printStackTrace(System.out);
return (Thread) m.invoke(null);
} catch(Exception e) {
log(() -> "Exception occured");
}
return null;
}

But I get into a circular loop and see stack traces like following :

java.lang.Throwable
at main.Main$ThreadMethodReplacements.currentThread(Main.java:218)
at java.lang.Thread.currentThread(Thread.java)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at main.Main$ThreadMethodReplacements.currentThread(Main.java:219)
at java.lang.Thread.currentThread(Thread.java)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at main.Main$ThreadMethodReplacements.currentThread(Main.java:219)
at java.lang.Thread.currentThread(Thread.java)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at main.Main$ThreadMethodReplacements.currentThread(Main.java:219)
at java.lang.Thread.currentThread(Thread.java)
at java.lang.ThreadLocal.get(ThreadLocal.java:160)
at net.bytebuddy.agent.builder.AgentBuilder$CircularityLock$Default.acquire(AgentBuilder.java:1926)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:10228)
at sun.instrument.TransformerManager.transform(TransformerManager.java:188)
at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:428)
at sun.misc.Unsafe.defineAnonymousClass(Native Method)
at java.lang.invoke.InnerClassLambdaMetafactory.spinInnerClass(InnerClassLambdaMetafactory.java:326)
at java.lang.invoke.InnerClassLambdaMetafactory.buildCallSite(InnerClassLambdaMetafactory.java:194)
at java.lang.invoke.LambdaMetafactory.metafactory(LambdaMetafactory.java:304)
at java.lang.invoke.CallSite.makeSite(CallSite.java:302)
at java.lang.invoke.MethodHandleNatives.linkCallSiteImpl(MethodHandleNatives.java:307)
at java.lang.invoke.MethodHandleNatives.linkCallSite(MethodHandleNatives.java:297)
at main.Main$ThreadMethodReplacements.currentThread(Main.java:216)
at java.lang.Thread.currentThread(Thread.java)
at java.lang.ThreadLocal.get(ThreadLocal.java:160)
at net.bytebuddy.agent.builder.AgentBuilder$CircularityLock$Default.acquire(AgentBuilder.java:1926)
at net.bytebuddy.agent.builder.AgentBuilder$RedefinitionStrategy$Collector$ForRetransformation.doApply(AgentBuilder.java:7191)
at net.bytebuddy.agent.builder.AgentBuilder$RedefinitionStrategy$Collector.apply(AgentBuilder.java:7034)
at net.bytebuddy.agent.builder.AgentBuilder$RedefinitionStrategy.apply(AgentBuilder.java:4870)
at net.bytebuddy.agent.builder.AgentBuilder$Default.doInstall(AgentBuilder.java:9507)
at net.bytebuddy.agent.builder.AgentBuilder$Default.installOn(AgentBuilder.java:9428)
at net.bytebuddy.agent.builder.AgentBuilder$Default$Delegator.installOn(AgentBuilder.java:11030)
at main.Main.premain(Main.java:142)
at main.Main.install(Main.java:83)
at main.Main.main(Main.java:67)

It feels like that I get into the loop because ByteBuddy itself uses Thread.currentThread(). 
Is there a configuration that I am missing? Is using the @Origin Method wrong for this? 
Or am I trying to achieve the impossible :)?

And my code for AgentBuilder is as follows:
Map<TypeDescription, byte[]> map = new HashMap<>();
map.put(new TypeDescription.ForLoadedType(Main.class), ClassFileLocator.ForClassLoader.read(Main.class));
map.put(new TypeDescription.ForLoadedType(Main.ThreadMethodReplacements.class), ClassFileLocator.ForClassLoader.read(Main.ThreadMethodReplacements.class));
File temp = Files.createTempDirectory("tmp").toFile();
ClassInjector.UsingInstrumentation.of(temp, ClassInjector.UsingInstrumentation.Target.BOOTSTRAP, instrumentation).inject(map);

new AgentBuilder.Default()
.ignore(nameStartsWith("net.bytebuddy."))
.disableClassFormatChanges()
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
.with(AgentBuilder.TypeStrategy.Default.REBASE)
.type(named("java.lang.Thread"))
.transform(new AgentBuilder.Transformer() {
@Override
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder,   TypeDescription typeDescription, ClassLoader classLoader, JavaModule module) {
     return builder.method(ElementMatchers.named("currentThread"))
   .intercept(MethodDelgation.to(Main.ThreadMethodReplacements.class));
 }
})
.with(AgentBuilder.Listener.StreamWriting.toSystemOut())
.installOn(instrumentation);





--
You received this message because you are subscribed to the Google Groups "Byte Buddy" group.
To unsubscribe from this group and stop receiving emails from it, send an email to byte-buddy+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/byte-buddy/de7a06be-67b7-4acf-9c78-4a9cb4be1565n%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages