Search in sources :

Example 1 with SerialVersionUIDAdder

use of org.objectweb.asm.commons.SerialVersionUIDAdder in project evosuite by EvoSuite.

the class BytecodeInstrumentation method transformBytes.

/**
 * <p>
 * transformBytes
 * </p>
 *
 * @param className
 *            a {@link java.lang.String} object.
 * @param reader
 *            a {@link org.objectweb.asm.ClassReader} object.
 * @return an array of byte.
 */
public byte[] transformBytes(ClassLoader classLoader, String className, ClassReader reader) {
    int readFlags = ClassReader.SKIP_FRAMES;
    if (Properties.INSTRUMENTATION_SKIP_DEBUG)
        readFlags |= ClassReader.SKIP_DEBUG;
    String classNameWithDots = ResourceList.getClassNameFromResourcePath(className);
    if (!checkIfCanInstrument(classNameWithDots)) {
        throw new RuntimeException("Should not transform a shared class (" + classNameWithDots + ")! Load by parent (JVM) classloader.");
    }
    TransformationStatistics.reset();
    /*
		 * To use COMPUTE_FRAMES we need to remove JSR commands. Therefore, we
		 * have a JSRInlinerAdapter in NonTargetClassAdapter as well as
		 * CFGAdapter.
		 */
    int asmFlags = ClassWriter.COMPUTE_FRAMES;
    ClassWriter writer = new ComputeClassWriter(asmFlags);
    ClassVisitor cv = writer;
    if (logger.isDebugEnabled()) {
        cv = new TraceClassVisitor(cv, new PrintWriter(System.err));
    }
    if (Properties.RESET_STATIC_FIELDS) {
        cv = new StaticAccessClassAdapter(cv, className);
    }
    if (Properties.PURE_INSPECTORS) {
        CheapPurityAnalyzer purityAnalyzer = CheapPurityAnalyzer.getInstance();
        cv = new PurityAnalysisClassVisitor(cv, className, purityAnalyzer);
    }
    if (Properties.MAX_LOOP_ITERATIONS >= 0) {
        cv = new LoopCounterClassAdapter(cv);
    }
    // Apply transformations to class under test and its owned classes
    if (DependencyAnalysis.shouldAnalyze(classNameWithDots)) {
        logger.debug("Applying target transformation to class " + classNameWithDots);
        if (!Properties.TEST_CARVING && Properties.MAKE_ACCESSIBLE) {
            cv = new AccessibleClassAdapter(cv, className);
        }
        cv = new RemoveFinalClassAdapter(cv);
        cv = new ExecutionPathClassAdapter(cv, className);
        cv = new CFGClassAdapter(classLoader, cv, className);
        if (Properties.EXCEPTION_BRANCHES) {
            cv = new ExceptionTransformationClassAdapter(cv, className);
        }
        if (Properties.ERROR_BRANCHES) {
            cv = new ErrorConditionClassAdapter(cv, className);
        }
    } else {
        logger.debug("Not applying target transformation");
        cv = new NonTargetClassAdapter(cv, className);
        if (Properties.MAKE_ACCESSIBLE) {
            cv = new AccessibleClassAdapter(cv, className);
        }
        // to create the CFG first
        if (Properties.TT && classNameWithDots.startsWith(Properties.CLASS_PREFIX)) {
            cv = new CFGClassAdapter(classLoader, cv, className);
        }
    }
    // Collect constant values for the value pool
    cv = new PrimitiveClassAdapter(cv, className);
    if (Properties.RESET_STATIC_FIELDS) {
        cv = handleStaticReset(className, cv);
    }
    // Mock instrumentation (eg File and TCP).
    if (TestSuiteWriterUtils.needToUseAgent()) {
        cv = new MethodCallReplacementClassAdapter(cv, className);
        /*
			 * If the class is serializable, then doing any change (adding hashCode, static reset, etc)
			 * will change the serialVersionUID if it is not defined in the class.
			 * Hence, if it is not defined, we have to define it to
			 * avoid problems in serialising the class, as reading Master will not do instrumentation.
			 * The serialVersionUID HAS to be the same as the un-instrumented class
			 */
        if (RuntimeSettings.applyUIDTransformation)
            cv = new SerialVersionUIDAdder(cv);
    }
    // Testability Transformations
    if (classNameWithDots.startsWith(Properties.PROJECT_PREFIX) || (!Properties.TARGET_CLASS_PREFIX.isEmpty() && classNameWithDots.startsWith(Properties.TARGET_CLASS_PREFIX)) || shouldTransform(classNameWithDots)) {
        ClassNode cn = new AnnotatedClassNode();
        reader.accept(cn, readFlags);
        logger.info("Starting transformation of " + className);
        if (Properties.STRING_REPLACEMENT) {
            StringTransformation st = new StringTransformation(cn);
            if (isTargetClassName(classNameWithDots) || shouldTransform(classNameWithDots))
                cn = st.transform();
        }
        ComparisonTransformation cmp = new ComparisonTransformation(cn);
        if (isTargetClassName(classNameWithDots) || shouldTransform(classNameWithDots)) {
            cn = cmp.transform();
            ContainerTransformation ct = new ContainerTransformation(cn);
            cn = ct.transform();
        }
        if (shouldTransform(classNameWithDots)) {
            logger.info("Testability Transforming " + className);
            BooleanTestabilityTransformation tt = new BooleanTestabilityTransformation(cn, classLoader);
            try {
                cn = tt.transform();
            } catch (Throwable t) {
                throw new Error(t);
            }
            logger.info("Testability Transformation done: " + className);
        }
        // -----
        cn.accept(cv);
        if (Properties.TEST_CARVING && TransformerUtil.isClassConsideredForInstrumentation(className)) {
            return handleCarving(className, writer);
        }
    } else {
        reader.accept(cv, readFlags);
    }
    return writer.toByteArray();
}
Also used : ClassVisitor(org.objectweb.asm.ClassVisitor) TraceClassVisitor(org.objectweb.asm.util.TraceClassVisitor) SerialVersionUIDAdder(org.objectweb.asm.commons.SerialVersionUIDAdder) BooleanTestabilityTransformation(org.evosuite.instrumentation.testability.BooleanTestabilityTransformation) TraceClassVisitor(org.objectweb.asm.util.TraceClassVisitor) CFGClassAdapter(org.evosuite.graphs.cfg.CFGClassAdapter) ComparisonTransformation(org.evosuite.instrumentation.testability.ComparisonTransformation) PrintWriter(java.io.PrintWriter) ContainerTransformation(org.evosuite.instrumentation.testability.ContainerTransformation) ClassNode(org.objectweb.asm.tree.ClassNode) ErrorConditionClassAdapter(org.evosuite.instrumentation.error.ErrorConditionClassAdapter) StringTransformation(org.evosuite.instrumentation.testability.StringTransformation) ClassWriter(org.objectweb.asm.ClassWriter) ComputeClassWriter(org.evosuite.runtime.util.ComputeClassWriter) CheapPurityAnalyzer(org.evosuite.assertion.CheapPurityAnalyzer) ComputeClassWriter(org.evosuite.runtime.util.ComputeClassWriter) PrimitiveClassAdapter(org.evosuite.seeding.PrimitiveClassAdapter)

Example 2 with SerialVersionUIDAdder

use of org.objectweb.asm.commons.SerialVersionUIDAdder in project atlas by alibaba.

the class TBIncrementalVisitor method instrumentClass.

@Nullable
public static File instrumentClass(int targetApiLevel, @NonNull File inputRootDirectory, @NonNull File inputFile, @NonNull File outputDirectory, @NonNull VisitorBuilder visitorBuilder, @NonNull ILogger logger, InjectErrorListener injectErrorListener, boolean addSerialVersionUID, boolean patchInitMethod, boolean patchEachMethod, boolean supportAddCallSuper, int count) throws IOException {
    byte[] classBytes;
    String path = FileUtils.relativePath(inputFile, inputRootDirectory);
    // the override class is requested.
    if (!isClassEligibleForInstantRun(inputFile)) {
        if (injectErrorListener != null) {
            injectErrorListener.onError(ErrorType.R_CLASS);
        }
        if (visitorBuilder.getOutputType() == OutputType.INSTRUMENT) {
            File outputFile = new File(outputDirectory, path);
            Files.createParentDirs(outputFile);
            Files.copy(inputFile, outputFile);
            return outputFile;
        } else {
            return null;
        }
    }
    classBytes = Files.toByteArray(inputFile);
    ClassReader classReader = new ClassReader(classBytes);
    // override the getCommonSuperClass to use the thread context class loader instead of
    // the system classloader. This is useful as ASM needs to load classes from the project
    // which the system classloader does not have visibility upon.
    // TODO: investigate if there is not a simpler way than overriding.
    ClassWriter classWriter = new ClassWriter(classReader, ClassWriter.COMPUTE_FRAMES) {

        @Override
        protected String getCommonSuperClass(final String type1, final String type2) {
            Class<?> c, d;
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            try {
                c = Class.forName(type1.replace('/', '.'), false, classLoader);
                d = Class.forName(type2.replace('/', '.'), false, classLoader);
            } catch (ClassNotFoundException e) {
                // This may happen if we're processing class files which reference APIs not
                // available on the target device. In this case return a dummy value, since this
                // is ignored during dx compilation.
                System.err.println("can not find superClass:" + type1 + " or " + type2);
                return "instant/run/NoCommonSuperClass";
            } catch (Throwable e) {
                throw new RuntimeException(type1 + ":" + type2, e);
            }
            if (c.isAssignableFrom(d)) {
                return type1;
            }
            if (d.isAssignableFrom(c)) {
                return type2;
            }
            if (c.isInterface() || d.isInterface()) {
                return "java/lang/Object";
            } else {
                do {
                    c = c.getSuperclass();
                } while (!c.isAssignableFrom(d));
                return c.getName().replace('.', '/');
            }
        }
    };
    ClassNode classNode = AsmUtils.readClass(classReader);
    boolean hasOtherMethod = false;
    if (classNode != null && classNode.methods != null) {
        for (Object methodNode : classNode.methods) {
            if (methodNode instanceof MethodNode) {
                if (!((MethodNode) methodNode).name.equals(ByteCodeUtils.CLASS_INITIALIZER) && !((MethodNode) methodNode).name.equals(ByteCodeUtils.CONSTRUCTOR)) {
                    hasOtherMethod = true;
                }
            }
        }
    }
    // when dealing with interface, we just copy the inputFile over without any changes unless
    // this is a package private interface.
    AccessRight accessRight = AccessRight.fromNodeAccess(classNode.access);
    File outputFile = new File(outputDirectory, path);
    if (!hasOtherMethod) {
        if (visitorBuilder.getOutputType() == OutputType.INSTRUMENT) {
            Files.createParentDirs(outputFile);
            Files.write(classBytes, outputFile);
            return outputFile;
        } else {
            return null;
        }
    }
    if ((classNode.access & Opcodes.ACC_INTERFACE) != 0) {
        if (visitorBuilder.getOutputType() == OutputType.INSTRUMENT) {
            // don't change the name of interfaces.
            if (injectErrorListener != null) {
                injectErrorListener.onError(ErrorType.INTERFACE);
            }
            Files.createParentDirs(outputFile);
            if (accessRight == AccessRight.PACKAGE_PRIVATE) {
                classNode.access = classNode.access | Opcodes.ACC_PUBLIC;
                classNode.accept(classWriter);
                Files.write(classWriter.toByteArray(), outputFile);
            } else {
                // just copy the input file over, no change.
                Files.write(classBytes, outputFile);
            }
            return outputFile;
        } else {
            return null;
        }
    }
    Class<?> c, d;
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    try {
        c = Class.forName(classNode.name.replace('/', '.'), false, classLoader);
        for (Imatcher imatcher : MatcherCreator.getMatchers()) {
            d = ((ImplementsMatcher) imatcher).getClazz(classLoader);
            if (d.isAssignableFrom(c)) {
                if (visitorBuilder.getOutputType() == OutputType.INSTRUMENT) {
                    // don't change the name of interfaces.
                    if (injectErrorListener != null) {
                        injectErrorListener.onError(ErrorType.IMPLEMENTS);
                    }
                    Files.createParentDirs(outputFile);
                    // just copy the input file over, no change.
                    Files.write(classBytes, outputFile);
                    return outputFile;
                } else {
                    return null;
                }
            }
        }
    } catch (Throwable e) {
        e.printStackTrace();
    }
    AsmUtils.DirectoryBasedClassReader directoryClassReader = new AsmUtils.DirectoryBasedClassReader(getBinaryFolder(inputFile, classNode));
    // if we are targeting a more recent version than the current device, disable instant run
    // for that class.
    List<ClassNode> parentsNodes = isClassTargetingNewerPlatform(targetApiLevel, TARGET_API_TYPE, directoryClassReader, classNode, logger) ? ImmutableList.of() : AsmUtils.parseParents(logger, directoryClassReader, classNode, targetApiLevel);
    // if we could not determine the parent hierarchy, disable instant run.
    if (parentsNodes.isEmpty() || isPackageInstantRunDisabled(inputFile)) {
        if (visitorBuilder.getOutputType() == OutputType.INSTRUMENT) {
            if (injectErrorListener != null) {
                if (parentsNodes.isEmpty()) {
                    injectErrorListener.onError(ErrorType.NEW_API);
                } else {
                    injectErrorListener.onError(ErrorType.PACKAGE_DISABLED);
                }
            }
            Files.createParentDirs(outputFile);
            Files.write(classBytes, outputFile);
            return outputFile;
        } else {
            return null;
        }
    }
    // Map<String, TBIncrementalSupportVisitor.MethodReference> methods = new HashMap<>();
    // for (ClassNode pN : parentsNodes) {
    // TBIncrementalSupportVisitor.addAllNewMethods(classNode,pN,methods, null);
    // }
    // if (methods.size() > count) {
    // if (visitorBuilder.getOutputType() == OutputType.INSTRUMENT) {
    // if (injectErrorListener != null) {
    // injectErrorListener.onError(ErrorType.SUB_EXCEEDED);
    // }
    // Files.createParentDirs(outputFile);
    // Files.write(classBytes, outputFile);
    // return outputFile;
    // } else {
    // return null;
    // }
    // }
    outputFile = new File(outputDirectory, visitorBuilder.getMangledRelativeClassFilePath(path));
    Files.createParentDirs(outputFile);
    IncrementalVisitor visitor = visitorBuilder.build(classNode, parentsNodes, classWriter, logger);
    if (visitor instanceof TBIncrementalSupportVisitor) {
        ((TBIncrementalSupportVisitor) visitor).setPatchInitMethod(patchInitMethod);
        ((TBIncrementalSupportVisitor) visitor).setSupportEachMethod(patchEachMethod);
        ((TBIncrementalSupportVisitor) visitor).setSupportAddCallSuper(supportAddCallSuper);
    }
    if (visitorBuilder.getOutputType() == OutputType.INSTRUMENT) {
        /*
             * Classes that do not have a serial version unique identifier, will be updated to
             * contain one. This is accomplished by using the {@link SerialVersionUIDAdder} class
             * visitor that is added when this visitor is created (see the constructor). This way,
             * the serialVersionUID is the same for instrumented and non-instrumented classes. All
             * classes will have a serialVersionUID, so if some of the classes that is extended
             * starts implementing {@link java.io.Serializable}, serialization and deserialization
             * will continue to work correctly.
             */
        if (addSerialVersionUID) {
            classNode.accept(new SerialVersionUIDAdder(visitor));
        } else {
            classNode.accept(visitor);
        }
    } else {
        classNode.accept(visitor);
    }
    Files.write(classWriter.toByteArray(), outputFile);
    return outputFile;
}
Also used : ClassNode(org.objectweb.asm.tree.ClassNode) SerialVersionUIDAdder(org.objectweb.asm.commons.SerialVersionUIDAdder) MethodNode(org.objectweb.asm.tree.MethodNode) File(java.io.File) Imatcher(com.taobao.android.builder.insant.matcher.Imatcher) Nullable(com.android.annotations.Nullable)

Aggregations

SerialVersionUIDAdder (org.objectweb.asm.commons.SerialVersionUIDAdder)2 ClassNode (org.objectweb.asm.tree.ClassNode)2 Nullable (com.android.annotations.Nullable)1 Imatcher (com.taobao.android.builder.insant.matcher.Imatcher)1 File (java.io.File)1 PrintWriter (java.io.PrintWriter)1 CheapPurityAnalyzer (org.evosuite.assertion.CheapPurityAnalyzer)1 CFGClassAdapter (org.evosuite.graphs.cfg.CFGClassAdapter)1 ErrorConditionClassAdapter (org.evosuite.instrumentation.error.ErrorConditionClassAdapter)1 BooleanTestabilityTransformation (org.evosuite.instrumentation.testability.BooleanTestabilityTransformation)1 ComparisonTransformation (org.evosuite.instrumentation.testability.ComparisonTransformation)1 ContainerTransformation (org.evosuite.instrumentation.testability.ContainerTransformation)1 StringTransformation (org.evosuite.instrumentation.testability.StringTransformation)1 ComputeClassWriter (org.evosuite.runtime.util.ComputeClassWriter)1 PrimitiveClassAdapter (org.evosuite.seeding.PrimitiveClassAdapter)1 ClassVisitor (org.objectweb.asm.ClassVisitor)1 ClassWriter (org.objectweb.asm.ClassWriter)1 MethodNode (org.objectweb.asm.tree.MethodNode)1 TraceClassVisitor (org.objectweb.asm.util.TraceClassVisitor)1