jtaint.StubAdapter.java Source code

Java tutorial

Introduction

Here is the source code for jtaint.StubAdapter.java

Source

/*
 *  Copyright 2009-2012 Michael Dalton
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package jtaint;

import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;

import java.util.BitSet;
import java.util.List;

/* XXX This handles all cases except when a subclass creates a less permissive
 * 'overriding' method (e.g., private) that cannot be invoked by other code.
 * In that case, we instrument the private method, but not the publicly
 * accessible 'overriden' method in the superclass, which could break things.
 * This gets really thorny if the overriding method is protected or default
 * access rather than private, so we ignore it for now since it shouldn't occur
 * in practice, at least for the classes we are instrumenting in the JDK.
 */

/** A simple adapter that, given a list of method prototypes, adds these methods
 * to the existing class if they are not found. Any methods that are added
 * merely call the superclass with the same method name and arguments. Useful
 * when all instrumentation must be performed in the current class, and some
 * methods are defined only in a superclass.
 */

public class StubAdapter extends ClassAdapter implements Opcodes {
    List stubList;
    BitSet found;
    String superName;

    public StubAdapter(ClassVisitor cv, List stubList) {
        super(cv);

        if (stubList == null)
            return;

        this.stubList = stubList;
        this.found = new BitSet(stubList.size());
    }

    public void visit(int version, int access, String name, String signature, String superName,
            String[] interfaces) {
        this.superName = superName;
        cv.visit(version, access, name, signature, superName, interfaces);
    }

    private void buildStub(MethodDecl m) {
        String name = m.name(), desc = m.type();
        int acc = m.access();
        Type[] args = Type.getArgumentTypes(desc);
        Type ret = Type.getReturnType(desc);

        /* We want any subclasses to visit the generated stub, so we invoke 
         * this.visitMethod() (which should be overridden by relevant
         * subclasses).
         */
        MethodVisitor mv = visitMethod(acc, name, desc, null, null);

        if (mv == null)
            return;

        mv.visitCode();

        int l = 1;
        mv.visitVarInsn(ALOAD, 0);

        for (int i = 0; i < args.length; l += args[i].getSize(), i++)
            mv.visitVarInsn(args[i].getOpcode(ILOAD), l);

        mv.visitMethodInsn(INVOKESPECIAL, superName, name, desc);
        mv.visitInsn(ret.getOpcode(IRETURN));

        mv.visitMaxs(Math.max(l, ret.getSize()), l);
        mv.visitEnd();
    }

    public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
        MethodDecl m = new MethodDecl(access, name, desc);

        if (stubList != null) {
            int i = stubList.indexOf(m);

            if (i != -1)
                found.set(i);
        }
        return cv.visitMethod(access, name, desc, signature, exceptions);
    }

    public final void visitEnd() {
        onBeginBuildStubs();

        if (stubList != null) {
            int len = stubList.size();
            for (int i = found.nextClearBit(0); i >= 0 && i < len; i = found.nextClearBit(i + 1))
                buildStub((MethodDecl) stubList.get(i));
        }

        onEndBuildStubs();
        cv.visitEnd();
    }

    protected void onBeginBuildStubs() {
    }

    protected void onEndBuildStubs() {
    }
}