Search in sources :

Example 71 with BadBytecode

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

the class FakeMethodCallManipulator method handleFakeMethodCall.

private void handleFakeMethodCall(ClassFile file, Set<MethodInfo> modifiedMethods, MethodInfo m, CodeIterator it, int index, int op, Data data) throws BadBytecode {
    // NOP out the whole thing
    it.writeByte(CodeIterator.NOP, index);
    it.writeByte(CodeIterator.NOP, index + 1);
    it.writeByte(CodeIterator.NOP, index + 2);
    if (op == CodeIterator.INVOKEINTERFACE) {
        // INVOKEINTERFACE has some extra parameters
        it.writeByte(CodeIterator.NOP, index + 3);
        it.writeByte(CodeIterator.NOP, index + 4);
    }
    // now we write some bytecode to invoke it directly
    final boolean staticMethod = data.getType() == Type.STATIC;
    Bytecode byteCode = new Bytecode(file.getConstPool());
    // stick the method number in the const pool then load it onto the
    // stack
    ManipulationUtils.pushParametersIntoArray(byteCode, data.getMethodDesc());
    int scind = file.getConstPool().addIntegerInfo(data.getMethodNumber());
    byteCode.addLdc(scind);
    byteCode.add(Opcode.SWAP);
    // invoke the added method
    if (staticMethod) {
        byteCode.addInvokestatic(data.getClassName(), Constants.ADDED_STATIC_METHOD_NAME, "(I[Ljava/lang/Object;)Ljava/lang/Object;");
    } else if (data.getType() == Type.INTERFACE) {
        byteCode.addInvokeinterface(data.getClassName(), Constants.ADDED_METHOD_NAME, "(I[Ljava/lang/Object;)Ljava/lang/Object;", 3);
    } else {
        byteCode.addInvokevirtual(data.getClassName(), Constants.ADDED_METHOD_NAME, "(I[Ljava/lang/Object;)Ljava/lang/Object;");
    }
    // cast it to the appropriate type and return it
    String returnType = DescriptorUtils.getReturnType(data.getMethodDesc());
    if (returnType.length() == 1 && !returnType.equals("V")) {
        Boxing.unbox(byteCode, returnType.charAt(0));
    } else if (returnType.equals("V")) {
        byteCode.add(Opcode.POP);
    } else {
        byteCode.addCheckcast(returnType.substring(1, returnType.length() - 1));
    }
    it.insertEx(byteCode.get());
    modifiedMethods.add(m);
}
Also used : BadBytecode(javassist.bytecode.BadBytecode) Bytecode(javassist.bytecode.Bytecode)

Example 72 with BadBytecode

use of javassist.bytecode.BadBytecode 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, classfileBuffer);
    }
    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, replaceable)) {
                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) {
                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() + "$FAILED.class");
                        dump.getParentFile().mkdirs();
                        FileOutputStream s = new FileOutputStream(dump);
                        DataOutputStream dos = new DataOutputStream(s);
                        file.write(dos);
                        s.close();
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }
                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 73 with BadBytecode

use of javassist.bytecode.BadBytecode 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, boolean replaceable) 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 74 with BadBytecode

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

the class ClassLoaderInstrumentation method redefineClassLoader.

/**
 * This method instruments class loaders so that they can load our helper
 * classes.
 */
@SuppressWarnings("unchecked")
public static boolean redefineClassLoader(ClassFile classFile, Set<MethodInfo> modifiedMethods) throws BadBytecode {
    boolean modified = false;
    for (MethodInfo method : (List<MethodInfo>) classFile.getMethods()) {
        if (Modifier.isStatic(method.getAccessFlags())) {
            continue;
        }
        if (method.getName().equals("loadClass") && (method.getDescriptor().equals("(Ljava/lang/String;)Ljava/lang/Class;") || method.getDescriptor().equals("(Ljava/lang/String;Z)Ljava/lang/Class;"))) {
            modifiedMethods.add(method);
            modified = true;
            if (method.getCodeAttribute().getMaxLocals() < 4) {
                method.getCodeAttribute().setMaxLocals(4);
            }
            // now we instrument the loadClass
            // if the system requests a class from the generated class package
            // then
            // we check to see if it is already loaded.
            // if not we try and get the class definition from GlobalData
            // we do not need to delegate as GlobalData will only
            // return the data to the correct classloader.
            // if the data is not null then we define the class, link
            // it if requested and return it.
            final CodeIterator iterator = method.getCodeAttribute().iterator();
            final Bytecode b = new Bytecode(classFile.getConstPool());
            b.addAload(1);
            b.addAload(0);
            b.addInvokestatic(ClassLookupManager.class.getName(), "getClassData", "(Ljava/lang/String;Ljava/lang/Object;)[B");
            b.add(Opcode.DUP);
            b.add(Opcode.IFNULL);
            JumpMarker jumpEnd = JumpUtils.addJumpInstruction(b);
            // now we need to do the findLoadedClasses thing
            b.addAload(0);
            b.addAload(1);
            b.addInvokevirtual("java.lang.ClassLoader", "findLoadedClass", "(Ljava/lang/String;)Ljava/lang/Class;");
            b.add(Opcode.DUP);
            b.add(Opcode.IFNULL);
            JumpMarker notFound = JumpUtils.addJumpInstruction(b);
            b.add(Opcode.ARETURN);
            notFound.mark();
            b.add(Opcode.POP);
            b.addAstore(3);
            b.addAload(0);
            b.addAload(1);
            b.addAload(3);
            b.addIconst(0);
            b.addAload(3);
            b.add(Opcode.ARRAYLENGTH);
            b.addInvokevirtual("java.lang.ClassLoader", "defineClass", "(Ljava/lang/String;[BII)Ljava/lang/Class;");
            if (method.getDescriptor().equals("Ljava/lang/String;Z)Ljava/lang/Class;")) {
                b.addIload(2);
            } else {
                b.addIconst(0);
            }
            b.add(Opcode.IFEQ);
            final JumpMarker linkJumpEnd = JumpUtils.addJumpInstruction(b);
            b.add(Opcode.DUP);
            b.addAload(0);
            b.add(Opcode.SWAP);
            b.addInvokevirtual("java.lang.ClassLoader", "resolveClass", "(Ljava/lang/Class;)V");
            linkJumpEnd.mark();
            b.add(Opcode.ARETURN);
            jumpEnd.mark();
            b.add(Opcode.POP);
            if (!classFile.getName().startsWith("java.") && !classFile.getName().startsWith("com.sun") && !classFile.getName().startsWith("sun") && !classFile.getName().startsWith("jdk.internal")) {
                // now we need to check if this is a fakereplace class
                // and if so always delegate to the appropriate loader
                b.addAload(1);
                b.addLdc("org.fakereplace");
                b.addInvokevirtual(String.class.getName(), "startsWith", "(Ljava/lang/String;)Z");
                b.add(Opcode.IFEQ);
                JumpMarker notFakereplace = JumpUtils.addJumpInstruction(b);
                // so this is a fakereplace class, delegate to the system loader
                b.addInvokestatic(ClassLoader.class.getName(), "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
                b.addAload(1);
                b.addInvokevirtual(ClassLoader.class.getName(), "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
                b.add(Opcode.ARETURN);
                notFakereplace.mark();
            }
            iterator.insert(b.get());
            method.getCodeAttribute().computeMaxStack();
        }
    }
    return modified;
}
Also used : JumpMarker(org.fakereplace.util.JumpMarker) CodeIterator(javassist.bytecode.CodeIterator) MethodInfo(javassist.bytecode.MethodInfo) List(java.util.List) BadBytecode(javassist.bytecode.BadBytecode) Bytecode(javassist.bytecode.Bytecode)

Example 75 with BadBytecode

use of javassist.bytecode.BadBytecode 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, boolean replaceable) 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)

Aggregations

BadBytecode (javassist.bytecode.BadBytecode)135 Bytecode (javassist.bytecode.Bytecode)57 CodeAttribute (javassist.bytecode.CodeAttribute)56 CodeIterator (javassist.bytecode.CodeIterator)43 MethodInfo (javassist.bytecode.MethodInfo)38 CtClass (javassist.CtClass)32 NotFoundException (javassist.NotFoundException)32 ConstPool (javassist.bytecode.ConstPool)30 Javac (javassist.compiler.Javac)27 CompileError (javassist.compiler.CompileError)26 CannotCompileException (javassist.CannotCompileException)22 ClassPool (javassist.ClassPool)12 List (java.util.List)11 Type (javassist.bytecode.analysis.Type)8 DuplicateMemberException (javassist.bytecode.DuplicateMemberException)7 IOException (java.io.IOException)6 CtMethod (javassist.CtMethod)5 ClassFile (javassist.bytecode.ClassFile)5 IllegalClassFormatException (java.lang.instrument.IllegalClassFormatException)4 Method (java.lang.reflect.Method)4