Search in sources :

Example 41 with MethodInfo

use of javassist.bytecode.MethodInfo in project fakereplace by fakereplace.

the class MainTransformer method transform.

@Override
public byte[] transform(final ClassLoader loader, final String className, final Class<?> classBeingRedefined, final ProtectionDomain protectionDomain, final byte[] classfileBuffer) throws IllegalClassFormatException {
    if (className == null) {
        // TODO: deal with lambdas
        return classfileBuffer;
    }
    boolean replaceable = Fakereplace.isClassReplaceable(className, loader);
    if (classBeingRedefined != null) {
        retransformationStarted = true;
        if (logClassRetransformation && replaceable) {
            log.info("Fakereplace is replacing class " + className);
        }
    }
    ChangedClassImpl changedClass = null;
    if (classBeingRedefined != null) {
        changedClass = new ChangedClassImpl(classBeingRedefined);
    }
    boolean changed = false;
    if (!replaceable && UnmodifiedFileIndex.isClassUnmodified(className)) {
        return null;
    }
    Set<Class<?>> classesToRetransform = new HashSet<>();
    final ClassFile file;
    try {
        Set<MethodInfo> modifiedMethods = new HashSet<>();
        file = new ClassFile(new DataInputStream(new ByteArrayInputStream(classfileBuffer)));
        for (final FakereplaceTransformer transformer : transformers) {
            if (transformer.transform(loader, className, classBeingRedefined, protectionDomain, file, classesToRetransform, changedClass, modifiedMethods)) {
                changed = true;
            }
        }
        if (!changed) {
            UnmodifiedFileIndex.markClassUnmodified(className);
            return null;
        } else {
            try {
                if (!modifiedMethods.isEmpty()) {
                    ClassPool classPool = new ClassPool();
                    if (loader == null) {
                        classPool.appendClassPath(new LoaderClassPath(ClassLoader.getSystemClassLoader()));
                    } else {
                        classPool.appendClassPath(new LoaderClassPath(loader));
                    }
                    classPool.appendSystemPath();
                    for (MethodInfo method : modifiedMethods) {
                        if (method.getCodeAttribute() != null) {
                            method.getCodeAttribute().computeMaxStack();
                            try {
                                method.rebuildStackMap(classPool);
                            } catch (BadBytecode e) {
                                Throwable root = e;
                                while (!(root instanceof NotFoundException) && root != null && root.getCause() != root) {
                                    root = root.getCause();
                                }
                                if (root instanceof NotFoundException) {
                                    NotFoundException cause = (NotFoundException) root;
                                    Bytecode bytecode = new Bytecode(file.getConstPool());
                                    bytecode.addNew(NoClassDefFoundError.class.getName());
                                    bytecode.add(Opcode.DUP);
                                    bytecode.addLdc(cause.getMessage());
                                    bytecode.addInvokespecial(NoClassDefFoundError.class.getName(), "<init>", "(Ljava/lang/String;)V");
                                    bytecode.add(Opcode.ATHROW);
                                    method.setCodeAttribute(bytecode.toCodeAttribute());
                                    method.getCodeAttribute().computeMaxStack();
                                    method.getCodeAttribute().setMaxLocals(DescriptorUtils.maxLocalsFromParameters(method.getDescriptor()) + 1);
                                    method.rebuildStackMap(classPool);
                                } else {
                                    throw e;
                                }
                            }
                        }
                    }
                }
            } catch (BadBytecode e) {
                throw new RuntimeException(e);
            }
            ByteArrayOutputStream bs = new ByteArrayOutputStream();
            file.write(new DataOutputStream(bs));
            // dump the class for debugging purposes
            final String dumpDir = AgentOptions.getOption(AgentOption.DUMP_DIR);
            if (dumpDir != null) {
                try {
                    File dump = new File(dumpDir + '/' + file.getName() + ".class");
                    dump.getParentFile().mkdirs();
                    FileOutputStream s = new FileOutputStream(dump);
                    DataOutputStream dos = new DataOutputStream(s);
                    file.write(dos);
                    s.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if (!classesToRetransform.isEmpty()) {
                synchronized (this) {
                    retransformationOutstandingCount++;
                }
                Thread t = new Thread(() -> {
                    try {
                        Fakereplace.getInstrumentation().retransformClasses(classesToRetransform.toArray(new Class[classesToRetransform.size()]));
                    } catch (UnmodifiableClassException e) {
                        log.error("Failed to retransform classes", e);
                    } finally {
                        synchronized (MainTransformer.this) {
                            retransformationOutstandingCount--;
                            notifyAll();
                        }
                    }
                });
                t.setDaemon(true);
                t.start();
            }
            if (classBeingRedefined != null) {
                changedClasses.add(changedClass);
                queueIntegration();
            }
            return bs.toByteArray();
        }
    } catch (IOException e) {
        e.printStackTrace();
        throw new IllegalClassFormatException(e.getMessage());
    } catch (Throwable e) {
        e.printStackTrace();
        throw new RuntimeException(e);
    }
}
Also used : DataOutputStream(java.io.DataOutputStream) ClassPool(javassist.ClassPool) NotFoundException(javassist.NotFoundException) IllegalClassFormatException(java.lang.instrument.IllegalClassFormatException) BadBytecode(javassist.bytecode.BadBytecode) Bytecode(javassist.bytecode.Bytecode) HashSet(java.util.HashSet) ClassFile(javassist.bytecode.ClassFile) UnmodifiableClassException(java.lang.instrument.UnmodifiableClassException) ChangedClassImpl(org.fakereplace.replacement.notification.ChangedClassImpl) LoaderClassPath(javassist.LoaderClassPath) ByteArrayOutputStream(java.io.ByteArrayOutputStream) IOException(java.io.IOException) DataInputStream(java.io.DataInputStream) BadBytecode(javassist.bytecode.BadBytecode) NotFoundException(javassist.NotFoundException) IllegalClassFormatException(java.lang.instrument.IllegalClassFormatException) IOException(java.io.IOException) UnmodifiableClassException(java.lang.instrument.UnmodifiableClassException) ByteArrayInputStream(java.io.ByteArrayInputStream) FileOutputStream(java.io.FileOutputStream) ChangedClass(org.fakereplace.api.ChangedClass) MethodInfo(javassist.bytecode.MethodInfo) ClassFile(javassist.bytecode.ClassFile) File(java.io.File)

Example 42 with MethodInfo

use of javassist.bytecode.MethodInfo in project fakereplace by fakereplace.

the class ClassInfoTransformer method transform.

@Override
public boolean transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, ClassFile file, Set<Class<?>> classesToRetransform, ChangedClassImpl changedClass, Set<MethodInfo> modifiedMethods) throws IllegalClassFormatException, BadBytecode, DuplicateMemberException {
    if (className.equals("com/sun/beans/introspect/ClassInfo")) {
        file.addInterface(Runnable.class.getName());
        MethodInfo run = new MethodInfo(file.getConstPool(), "run", "()V");
        run.setAccessFlags(AccessFlag.PUBLIC);
        Bytecode b = new Bytecode(file.getConstPool(), 1, 1);
        b.addGetstatic(file.getName(), "CACHE", "Lcom/sun/beans/util/Cache;");
        b.addInvokevirtual("com/sun/beans/util/Cache", "clear", "()V");
        b.add(Opcode.RETURN);
        run.setCodeAttribute(b.toCodeAttribute());
        file.addMethod(run);
        MethodInfo m = file.getMethod("<init>");
        CodeIterator iterator = m.getCodeAttribute().iterator();
        int pos = 0;
        while (iterator.hasNext()) {
            pos = iterator.next();
        }
        b = new Bytecode(file.getConstPool(), 1, 0);
        b.add(Bytecode.ALOAD_0);
        b.addPutstatic(ClassInfoTransformer.class.getName(), "clearAction", "Ljava/lang/Runnable;");
        iterator.insert(pos, b.get());
        m.getCodeAttribute().computeMaxStack();
        return true;
    }
    return false;
}
Also used : CodeIterator(javassist.bytecode.CodeIterator) MethodInfo(javassist.bytecode.MethodInfo) BadBytecode(javassist.bytecode.BadBytecode) Bytecode(javassist.bytecode.Bytecode)

Example 43 with MethodInfo

use of javassist.bytecode.MethodInfo in project fakereplace by fakereplace.

the class MethodReplacementTransformer method createRemovedMethod.

private static MethodInfo createRemovedMethod(ClassFile file, MethodData md, Class<?> oldClass, Set<MethodData> methodsToRemove) {
    if (md.getMethodName().equals("<clinit>")) {
        // if the static constructor is removed it gets added later on
        return null;
    // in the process
    }
    // load up the existing method object
    MethodInfo m = new MethodInfo(file.getConstPool(), md.getMethodName(), md.getDescriptor());
    m.setAccessFlags(md.getAccessFlags());
    // put the old annotations on the class
    if (md.getMethodName().equals("<init>")) {
        Constructor<?> meth;
        try {
            meth = md.getConstructor(oldClass);
        } catch (Exception e) {
            throw new RuntimeException("Error accessing existing constructor via reflection in not found", e);
        }
        m.addAttribute(AnnotationReplacer.duplicateAnnotationsAttribute(file.getConstPool(), meth));
    } else {
        Method meth;
        try {
            meth = md.getMethod(oldClass);
        } catch (Exception e) {
            throw new RuntimeException("Error accessing existing method via reflection in not found", e);
        }
        m.addAttribute(AnnotationReplacer.duplicateAnnotationsAttribute(file.getConstPool(), meth));
    }
    Bytecode b = new Bytecode(file.getConstPool(), 5, 3);
    b.addNew("java.lang.NoSuchMethodError");
    b.add(Opcode.DUP);
    b.addInvokespecial("java.lang.NoSuchMethodError", "<init>", "()V");
    b.add(Bytecode.ATHROW);
    CodeAttribute ca = b.toCodeAttribute();
    m.setCodeAttribute(ca);
    try {
        ca.computeMaxStack();
        file.addMethod(m);
    } catch (DuplicateMemberException e) {
        logger.error("Duplicate error", e);
    } catch (BadBytecode e) {
        logger.error("Bad bytecode", e);
    }
    methodsToRemove.add(md);
    return m;
}
Also used : DuplicateMemberException(javassist.bytecode.DuplicateMemberException) CodeAttribute(javassist.bytecode.CodeAttribute) MethodInfo(javassist.bytecode.MethodInfo) BadBytecode(javassist.bytecode.BadBytecode) Bytecode(javassist.bytecode.Bytecode) Method(java.lang.reflect.Method) DuplicateMemberException(javassist.bytecode.DuplicateMemberException) IllegalClassFormatException(java.lang.instrument.IllegalClassFormatException) IOException(java.io.IOException) BadBytecode(javassist.bytecode.BadBytecode)

Example 44 with MethodInfo

use of javassist.bytecode.MethodInfo in project fakereplace by fakereplace.

the class ResteasyTransformer method transform.

@Override
public boolean transform(final ClassLoader loader, final String className, final Class<?> classBeingRedefined, final ProtectionDomain protectionDomain, final ClassFile file, Set<Class<?>> classesToRetransform, ChangedClassImpl changedClass, Set<MethodInfo> modifiedMethods) throws IllegalClassFormatException, BadBytecode {
    try {
        if (file.getName().equals(ResteasyExtension.FILTER_DISPATCHER)) {
            FieldInfo field = new FieldInfo(file.getConstPool(), FIELD_NAME, FILTER_FIELD_TYPE);
            field.setAccessFlags(Modifier.PUBLIC);
            file.addField(field);
            field = new FieldInfo(file.getConstPool(), PARAMETER_FIELD_NAME, SET_TYPE);
            field.setAccessFlags(Modifier.PUBLIC);
            file.addField(field);
            for (final MethodInfo method : (List<MethodInfo>) file.getMethods()) {
                if (method.getName().equals("init") && method.getDescriptor().equals("(Ljavax/servlet/FilterConfig;)V")) {
                    method.setAccessFlags(method.getAccessFlags() | AccessFlag.SYNCHRONIZED);
                    modifiedMethods.add(method);
                    final Bytecode b = new Bytecode(file.getConstPool());
                    b.addAload(0);
                    b.addNew(RESTEASY_FILTER_CONFIG);
                    b.add(Opcode.DUP);
                    b.addAload(1);
                    b.addInvokespecial(RESTEASY_FILTER_CONFIG, "<init>", "(Ljavax/servlet/FilterConfig;)V");
                    b.addPutfield(ResteasyExtension.FILTER_DISPATCHER, FIELD_NAME, FILTER_FIELD_TYPE);
                    b.addAload(1);
                    b.addInvokeinterface("javax/servlet/FilterConfig", "getServletContext", "()Ljavax/servlet/ServletContext;", 1);
                    b.addAload(0);
                    b.addGetfield(ResteasyExtension.FILTER_DISPATCHER, PARAMETER_FIELD_NAME, SET_TYPE);
                    b.addInvokestatic(CONTEXT_PARAMS, "init", INIT_METHOD_DESC);
                    b.addAload(0);
                    b.add(Opcode.SWAP);
                    b.addPutfield(ResteasyExtension.FILTER_DISPATCHER, PARAMETER_FIELD_NAME, SET_TYPE);
                    method.getCodeAttribute().iterator().insert(b.get());
                    method.getCodeAttribute().computeMaxStack();
                } else if (method.getName().equals("<init>")) {
                    // no idea why this is needed
                    method.getCodeAttribute().setMaxStack(1);
                } else if (method.getName().equals("getDispatcher")) {
                    method.setAccessFlags(method.getAccessFlags() | AccessFlag.SYNCHRONIZED);
                    modifiedMethods.add(method);
                }
            }
            return true;
        } else if (file.getName().equals(ResteasyExtension.SERVLET_DISPATCHER)) {
            FieldInfo field = new FieldInfo(file.getConstPool(), FIELD_NAME, SERVLET_FIELD_TYPE);
            field.setAccessFlags(Modifier.PUBLIC);
            file.addField(field);
            field = new FieldInfo(file.getConstPool(), PARAMETER_FIELD_NAME, SET_TYPE);
            field.setAccessFlags(Modifier.PUBLIC);
            file.addField(field);
            for (final MethodInfo method : (List<MethodInfo>) file.getMethods()) {
                if (method.getName().equals("init") && method.getDescriptor().equals("(Ljavax/servlet/ServletConfig;)V")) {
                    method.setAccessFlags(method.getAccessFlags() | AccessFlag.SYNCHRONIZED);
                    modifiedMethods.add(method);
                    final Bytecode b = new Bytecode(file.getConstPool());
                    b.addAload(0);
                    b.addNew(RESTEASY_SERVLET_CONFIG);
                    b.add(Opcode.DUP);
                    b.addAload(1);
                    b.addInvokespecial(RESTEASY_SERVLET_CONFIG, "<init>", "(Ljavax/servlet/ServletConfig;)V");
                    b.addPutfield(ResteasyExtension.SERVLET_DISPATCHER, FIELD_NAME, SERVLET_FIELD_TYPE);
                    b.addAload(1);
                    b.addInvokeinterface("javax/servlet/ServletConfig", "getServletContext", "()Ljavax/servlet/ServletContext;", 1);
                    b.addAload(0);
                    b.addGetfield(ResteasyExtension.SERVLET_DISPATCHER, PARAMETER_FIELD_NAME, SET_TYPE);
                    b.addInvokestatic(CONTEXT_PARAMS, "init", INIT_METHOD_DESC);
                    b.addAload(0);
                    b.add(Opcode.SWAP);
                    b.addPutfield(ResteasyExtension.SERVLET_DISPATCHER, PARAMETER_FIELD_NAME, SET_TYPE);
                    method.getCodeAttribute().iterator().insert(b.get());
                    method.getCodeAttribute().computeMaxStack();
                } else if (method.getName().equals("<init>")) {
                    method.getCodeAttribute().setMaxStack(1);
                } else if (method.getName().equals("getDispatcher")) {
                    method.setAccessFlags(method.getAccessFlags() | AccessFlag.SYNCHRONIZED);
                    modifiedMethods.add(method);
                }
            }
            return true;
        }
    } catch (DuplicateMemberException e) {
        throw new RuntimeException(e);
    }
    return false;
}
Also used : DuplicateMemberException(javassist.bytecode.DuplicateMemberException) MethodInfo(javassist.bytecode.MethodInfo) List(java.util.List) BadBytecode(javassist.bytecode.BadBytecode) Bytecode(javassist.bytecode.Bytecode) FieldInfo(javassist.bytecode.FieldInfo)

Example 45 with MethodInfo

use of javassist.bytecode.MethodInfo in project fakereplace by fakereplace.

the class WildflyHibernate5ClassTransformer method transform.

@Override
public boolean transform(final ClassLoader loader, final String className, final Class<?> classBeingRedefined, final ProtectionDomain protectionDomain, final ClassFile file, Set<Class<?>> classesToRetransform, ChangedClassImpl changedClass, Set<MethodInfo> modifiedMethods) throws IllegalClassFormatException, BadBytecode, DuplicateMemberException {
    if (file.getName().equals("org.jboss.as.jpa.service.PersistenceUnitServiceImpl")) {
        for (MethodInfo method : (List<MethodInfo>) file.getMethods()) {
            if (method.getName().equals("getEntityManagerFactory")) {
                modifiedMethods.add(method);
                // need to save the method params so we can re-use them when we re-create our EMF
                Bytecode s = new Bytecode(file.getConstPool());
                // we need to interceptor the return value
                // and add in our own bytecode fragment.
                // first lets create our proxy creation code
                final Bytecode b = new Bytecode(file.getConstPool());
                b.addNew(PROXY_NAME);
                b.add(Opcode.DUP);
                b.addAload(0);
                b.addInvokespecial(PROXY_NAME, "<init>", "(Lorg/jipijapa/plugin/spi/PersistenceUnitService;)V");
                insertBeforeReturn(method, s, b);
            }
        }
        file.addInterface(HackPersistenceUnitService.class.getName());
        Bytecode bc = new Bytecode(file.getConstPool(), 1, 1);
        bc.addAload(0);
        bc.addGetfield("org.jboss.as.jpa.service.PersistenceUnitServiceImpl", "entityManagerFactory", "Ljavax/persistence/EntityManagerFactory;");
        bc.addOpcode(Bytecode.ARETURN);
        MethodInfo methodInfo = new MethodInfo(file.getConstPool(), "emf", "()Ljavax/persistence/EntityManagerFactory;");
        methodInfo.setAccessFlags(AccessFlag.PUBLIC);
        methodInfo.setCodeAttribute(bc.toCodeAttribute());
        file.addMethod(methodInfo);
        modifiedMethods.add(methodInfo);
        return true;
    } else {
        return false;
    }
}
Also used : MethodInfo(javassist.bytecode.MethodInfo) List(java.util.List) BadBytecode(javassist.bytecode.BadBytecode) Bytecode(javassist.bytecode.Bytecode)

Aggregations

MethodInfo (javassist.bytecode.MethodInfo)54 Bytecode (javassist.bytecode.Bytecode)28 BadBytecode (javassist.bytecode.BadBytecode)19 CodeIterator (javassist.bytecode.CodeIterator)18 CodeAttribute (javassist.bytecode.CodeAttribute)17 ConstPool (javassist.bytecode.ConstPool)17 ClassFile (javassist.bytecode.ClassFile)12 LocalVariableAttribute (javassist.bytecode.LocalVariableAttribute)10 DuplicateMemberException (javassist.bytecode.DuplicateMemberException)9 List (java.util.List)7 ClassPool (javassist.ClassPool)7 ByteArrayOutputStream (java.io.ByteArrayOutputStream)6 DataOutputStream (java.io.DataOutputStream)6 IOException (java.io.IOException)6 CtMethod (javassist.CtMethod)6 HashMap (java.util.HashMap)5 HashSet (java.util.HashSet)5 Set (java.util.Set)5 AnnotationsAttribute (javassist.bytecode.AnnotationsAttribute)5 IllegalClassFormatException (java.lang.instrument.IllegalClassFormatException)4