Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
180 views
in Technique[技术] by (71.8m points)

Java: Cannot redefine class during instrumentation on attach

I have a simple application that creates and uses instances of ToChange class in a loop:

public class ToChange {
  private int i;
  public ToChange(int i) {
    this.i = i;
  }

  public void print() {
    System.out.println(i);
  }
}
public class MyApplication {
  public static void main(String[] args) {
    System.out.println("pid = " + ProcessHandle.current().pid());
    int i = 0;
    // This is an instance for the whole application lifecycle
    var wholeAppInstance = new ToChange(0);

    while (true) {
      // Use the wholeAppInstance first
      wholeAppInstance.print();

      // Create and use a new instance in each loop
      new ToChange(++i).print();

      System.out.println("------------");
      try {
        Thread.sleep(3000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }
}

While the application runs, there are such lines in the console:

0
1
------------
0
2
------------
0
3
------------

I also have an attach application that loads an agent and attaches it to a running JVM. It takes two arguments, the first is the pid of a the running JVM process and the second is the path of the agent that will be attached:

// The main class of the attach application
public class Main {
  public static void main(String[] args) throws IOException, AttachNotSupportedException, AgentLoadException, AgentInitializationException {
    String processId = args[0];
    String agentJar = args[1];
    VirtualMachine virtualMachine = VirtualMachine.attach(processId);
    try {
      virtualMachine.loadAgent(agentJar);
    } catch (Exception error) {
      error.printStackTrace();
    } finally {
      virtualMachine.detach();
    }
  }
}

Finally, I have the agent, which redefines the ToChange class:

public class MyAgentMain {
  public static void agentmain(String arg, Instrumentation instrumentation) throws Exception {
    System.out.println("Agent mark 1");
    Class<?> toChange = Class.forName("org.abc.security.attach.application.ToChange");

    System.out.println("Agent mark 2");
    ByteArrayOutputStream output = new ByteArrayOutputStream();

    try (InputStream input = MyAgentMain
            .class
            .getResourceAsStream("/org/abc/security/attach/application/ToChange.class")) {
      System.out.println("input reference: " + input);
      byte[] buffer = new byte[1024];
      int length;
      while ((length = input.read(buffer)) != -1) {
        output.write(buffer, 0, length);
      }
      System.out.println("Agent mark 3");
    } catch (Exception error) {
      error.printStackTrace();
    }

    instrumentation.redefineClasses(new ClassDefinition(toChange, output.toByteArray()));
    System.out.println("Agent mark 4");
  }
}

The MANIFEST.MF of the agent contains the following:

Manifest-Version: 1.0
Created-By: Maven Jar Plugin 3.2.0
Build-Jdk-Spec: 11
Agent-Class: org.abc.security.attach.agent.MyAgentMain
Can-Redefine-Classes: true

And the ToChange class is changed to the following:

public class ToChange {
  private int i;

  public ToChange(int i) {
    this.i = i;
  }

  public void print() {
    System.out.println("Changed:" + this.i);
  }
}

I execute the attach application, passing the pid of the running MyApplication and the agent location:

java --add-modules jdk.attach -jar attach-0.1.0-SNAPSHOT.jar $PID agent-0.1.0-SNAPSHOT.jar

I see in the MyApplication console the printlns produced by the agent and there are no errors neither in the MyApplication console, nor in the agent console.

However, after the agent completes, I still see the same output in MyApplication:

------------
0
7
------------
Agent mark 1
Agent mark 2
input reference: java.io.BufferedInputStream@540e6237
Agent mark 3
Agent mark 4
0
8
------------
0
9
------------

I would expect that since there are no errors, the instrumentation succeeds, the ChangeTo class gets redefined and the printlns are different. However, this is not the case...

What I am doing (or expecting) wrong?


EDITED to answer my question

@johannes-kuhn 's reply gave me the idea to try changing the redefined class location in the agent, in order not to be under the same path with the original.

It seems that the "resources" of the final, instrumented MyApplication remained unchanged, because the redefined class had the same path in the resources with the old one. Changing the location of the ToChange class in the agent resources, did the trick!

For clarity, here is the working MyAgentMain:

public class MyAgentMain {
  public static void agentmain(String arg, Instrumentation instrumentation) throws Exception {
    System.out.println("Agent mark 1");
    Class<?> license = Class.forName("org.abc.security.attach.application.ToChange");

    System.out.println("Agent mark 2");
    ByteArrayOutputStream output = new ByteArrayOutputStream();

    try (InputStream input = MyAgentMain
            .class
            .getResourceAsStream("/ToChange.class")) { // THE NON-WORKING VERSION HAD /org/abc/security/attach/application/ToChange.class
      System.out.println("input reference: " + input);
      byte[] buffer = new byte[1024];
      int length;
      while ((length = input.read(buffer)) != -1) {
        output.write(buffer, 0, length);
      }
      System.out.println("Agent mark 3");
    } catch (Exception error) {
      error.printStackTrace();
    }

    instrumentation.redefineClasses(new ClassDefinition(license, output.toByteArray()));
    System.out.println("Agent mark 4");
  }
}

question from:https://stackoverflow.com/questions/65914608/java-cannot-redefine-class-during-instrumentation-on-attach

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...