0

I'm trying to change the bytecode of java.lang.StringBuilder according to this SO answer:

Replace a class within the Java class library with a custom version

However it looks like it does not intercept java.lang.StringBuilder. Does anyone know why?

The agent:

import java.lang.instrument.*;
import java.security.*;
import java.io.*;

public class BugFixAgent {
  public static void premain(String args, Instrumentation inst) {
    inst.addTransformer(new ClassFileTransformer() {
      @Override
      public byte[] transform(ClassLoader loader,
                              String className,
                              Class<?> classBeingRedefined,
                              ProtectionDomain protectionDomain,
                              byte[] classfileBuffer) {

                System.out.println("---- ClassName: " + className);
                return null;
      }
    }, true);
  }
}

The test code:

package com.test;

public class Test {

        public static void main(String[] args) {
                StringBuilder sb = new StringBuilder();
                sb.append("Blah");
                sb.append(34.4f);
                System.out.println(sb);
        }
}

But when I execute with:

java -javaagent:agentclass/bugfixagent.jar -cp classes com.test.Test

I get:

---- ClassName: java/lang/invoke/MethodHandleImpl
---- ClassName: java/lang/invoke/MethodHandleImpl$1
---- ClassName: java/lang/invoke/MethodHandleImpl$2
---- ClassName: java/util/function/Function
---- ClassName: java/lang/invoke/MethodHandleImpl$3
---- ClassName: java/lang/invoke/MethodHandleImpl$4
---- ClassName: java/lang/ClassValue
---- ClassName: java/lang/ClassValue$Entry
---- ClassName: java/lang/ClassValue$Identity
---- ClassName: java/lang/ClassValue$Version
---- ClassName: java/lang/invoke/MemberName$Factory
---- ClassName: java/lang/invoke/MethodHandleStatics
---- ClassName: java/lang/invoke/MethodHandleStatics$1
---- ClassName: sun/misc/PostVMInitHook
---- ClassName: sun/usagetracker/UsageTrackerClient
---- ClassName: java/util/concurrent/atomic/AtomicBoolean
---- ClassName: sun/usagetracker/UsageTrackerClient$1
---- ClassName: sun/usagetracker/UsageTrackerClient$4
---- ClassName: sun/usagetracker/UsageTrackerClient$3
---- ClassName: java/io/FileOutputStream$1
---- ClassName: sun/launcher/LauncherHelper
---- ClassName: java/util/concurrent/ConcurrentHashMap$ForwardingNode
---- ClassName: sun/misc/URLClassPath$FileLoader$1
---- ClassName: java/lang/Package
---- ClassName: com/test/Test
---- ClassName: sun/launcher/LauncherHelper$FXHelper
---- ClassName: java/lang/Class$MethodArray
---- ClassName: java/lang/Void
---- ClassName: sun/misc/FloatingDecimal
---- ClassName: sun/misc/FloatingDecimal$ExceptionalBinaryToASCIIBuffer
---- ClassName: sun/misc/FloatingDecimal$BinaryToASCIIConverter
---- ClassName: sun/misc/FloatingDecimal$BinaryToASCIIBuffer
---- ClassName: sun/misc/FloatingDecimal$1
---- ClassName: sun/misc/FloatingDecimal$PreparedASCIIToBinaryBuffer
---- ClassName: sun/misc/FloatingDecimal$ASCIIToBinaryConverter
---- ClassName: sun/misc/FDBigInteger
Blah34.4
---- ClassName: java/lang/Shutdown
---- ClassName: java/lang/Shutdown$Lock

Where did java.lang.StringBuilder go ??? Why is it not there?


java.lang.String is not there either, probably because it was loaded before. How do I intercept java.lang.String? Impossible?

LatencyFighter
  • 351
  • 2
  • 11
  • I wonder if it got initialized before your premain? After all, your premain method will itself use `StringBuilder`... – Louis Wasserman Feb 06 '18 at 18:32
  • Wow, are you talking about this `System.out.println("---- ClassName: " + className);` ? – LatencyFighter Feb 06 '18 at 18:33
  • Yes, I am talking about that line. – Louis Wasserman Feb 06 '18 at 18:34
  • I changed to `System.out.println(className);` with same issue. Maybe I cannot use `System.out.println` at all ??? How would I know then? – LatencyFighter Feb 06 '18 at 18:36
  • You may just be straight up out of luck with things that will have to get initialized before any Java code at all is run. – Louis Wasserman Feb 06 '18 at 18:39
  • Of course, since your `premain` method receives a `String` argument, that class has already been loaded before your Agent starts. And it’s very likely that `StringBuilder` has been loaded too, a) because of dependencies between `String` and `StringBuilder` or b) because the JRE uses it itself, e.g. when processing the arguments. So there is no way to do load-time transformation, but only retransforming, of course, subject to certain limitations. But even if you manage to instrument that class, it’s possible that certain changes are bypassed by the JVM’s string concatenation optimizations. – Holger Feb 08 '18 at 17:18

0 Answers0