nullpointer的原因

时间:2012-02-11 18:55:35

标签: java

你好我一直试图找出这个错误很长一段时间了。我有一个nullpointer的新问题,这里是类:

编辑:该程序旨在将代码注入另一个类,以阻止它在加载时删除类,然后它反映类文件(存储为字节数组),然后转储到类文件。

我已经评论了与堆栈跟踪相对应的行号

public class Program {

private HashMap<String, ClassGen> myClass = new HashMap<String, ClassGen>();
private int array_index;

/**
 * Constructor.
 */
public Program() {
    try {
        File Jar1 = new File("Jar1.jar");
        File nJar1 = new File("nJar1.jar");
        File OutPutJar = new File("Out.jar");
        BAppletStub stub = new BAppletStub();
        injectLoader();
        dumpClientFiles(stub); // Line 65
        JarFile theJar = new JarFile(OutPutJar);
        Enumeration<?> en = theJar.entries();
        while (en.hasMoreElements()) {
            JarEntry entry = (JarEntry) en.nextElement();
            if (entry.getName().endsWith(".class")) {
                ClassParser cp = new ClassParser(theJar.getInputStream(entry), entry.getName());
                JavaClass jc = cp.parse();
                ClassGen cg = new ClassGen(jc);
                myClass.put(cg.getClassName(), cg);
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

private void injectLoader() throws IOException {
    JarFile theJar = new JarFile("Jar1.jar");
    FileOutputStream stream = new FileOutputStream("nJar1.jar");
    JarOutputStream out = new JarOutputStream(stream);
    Enumeration<?> en = theJar.entries();
    while (en.hasMoreElements()) {
        JarEntry entry = (JarEntry) en.nextElement();
        if (entry.getName().contains("META-INF"))
            continue;
        JarEntry je = new JarEntry(entry.getName());
        out.putNextEntry(je);
        if (entry.getName().endsWith(".class")) {
            ClassParser cp = new ClassParser(theJar.getInputStream(entry), entry.getName());
            JavaClass jc = cp.parse();
            ClassGen cg = new ClassGen(jc);
            fixClass(cg);
            out.write(cg.getJavaClass().getBytes());
        } else {
            InputStream in = theJar.getInputStream(entry);
            int read;
            byte[] buffer = new byte[1024];
            while ((read = in.read(buffer)) != -1) {
                out.write(buffer, 0, read);
            }
        }
    }
    out.close();
    stream.close();
}

@SuppressWarnings({ "deprecation", "unchecked" })
private void fixClass(ClassGen cg) {
    for (Method m : cg.getMethods()) {
        if (m.getReturnType().equals(Type.CLASS)) {
            MethodGen mg = new MethodGen(m, cg.getClassName(), cg.getConstantPool());
            InstructionList list = mg.getInstructionList();
            String pattern = "aaload checkcast aload invokevirtual";
            InstructionFinder finder = new InstructionFinder(list);
            Iterator<InstructionHandle[]> it = finder.search(pattern);
            while (it.hasNext()) {
                InstructionHandle[] handles = it.next();
                INVOKEVIRTUAL invoke = (INVOKEVIRTUAL) handles[3].getInstruction();
                if (invoke.getMethodName(cg.getConstantPool()).equals("remove") && invoke.getClassName(cg.getConstantPool()).contains("Hashtable")) {
                    InstructionFactory factory = new InstructionFactory(cg);
                    Instruction i = factory.createInvoke("java/util/Hashtable", "get", invoke.getReturnType(cg.getConstantPool()), invoke.getArgumentTypes(cg.getConstantPool()), Constants.INVOKEVIRTUAL);
                    InstructionHandle handle = list.insert(handles[3], i);
                    InstructionHandle h = handles[3];
                    if (h.hasTargeters()) {
                        for (InstructionTargeter t : h.getTargeters()) {
                            t.updateTarget(h, handle);
                        }
                    }
                    try {
                        list.delete(h);
                    } catch (TargetLostException e) {
                        e.printStackTrace();
                    }
                    mg.setMaxLocals();
                    mg.setMaxStack();
                    cg.replaceMethod(m, mg.getMethod());
                    return;
                }
            }
        }
    }
}

private void dumpClientFiles(BAppletStub stub) {
    try {
        File f = new File("nJar1.jar");
        URLClassLoader loader = new URLClassLoader(new URL[] { f.toURI().toURL() });
        Class<?> g = loader.loadClass("Rs2Applet");
        final Applet a = (Applet) g.newInstance();
        a.setStub(stub);
        a.init();
        Object[] objs = getObjects(g, a); // Line 237
        if (objs == null)
            System.exit(1);
        Hashtable<?, ?> tempTable = (Hashtable<?, ?>) objs[array_index];
        JarOutputStream out = new JarOutputStream(new FileOutputStream("Out.jar"));
        Enumeration<?> it = tempTable.keys();
        int classes_dumped = 0;
        while (it.hasMoreElements()) {
            String s = (String) it.nextElement();
            Object o = tempTable.get(s);
            JarEntry entry = new JarEntry(s.replace(".", "/") + ".class");
            out.putNextEntry(entry);
            out.write((byte[]) o);
            out.closeEntry();
            classes_dumped++;
        }
        System.out.println("Dumped " + classes_dumped + " classes to Out.jar");
        out.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public Object[] getObjects(Class<?> clazz, Object object) throws IllegalArgumentException, IllegalAccessException {
    Field fd = null;
    Field arr = null;
    for (Field field : clazz.getDeclaredFields()) {
        if ((field.getModifiers() & Modifier.PRIVATE) != 0 && field.getType().getCanonicalName().equals("java.lang.Object[]")) {
            if (fd == null) {
                fd = field;
            } else {
                arr = field;
            }
        }
    }
    Object[] objs = null;
    boolean found = false;
    Field array_field = null;
    outer: for (int i = 0; i < 2 && !found; i++) {
        array_field = (array_field == null || array_field == arr) ? fd : arr;
        if (!array_field.isAccessible()) { //Line 278
            array_field.setAccessible(true);
        }
        objs = (Object[]) array_field.get(object);
        for (int j = 0; j < objs.length; j++) {
            Object o = objs[j];
            if (o instanceof Hashtable) {
                found = true;
                if (((Hashtable<?, ?>) o).values().iterator().next().getClass().getCanonicalName().equals("byte[]")) {
                    array_index = j;
                    break outer;
                }
            }
        }
    }
    if (fd.isAccessible())
        fd.setAccessible(false);
    if (arr.isAccessible())
        arr.setAccessible(false);
    return objs;
}

public static void main(String[] args) {
    new Program(); //Line 304
}
}

这是堆栈跟踪:

java.lang.NullPointerException
at org.nick.program.getObjects(program.java:278)
at org.nick.program.dumpFiles(program.java:237)
at org.nick.program.<init>(program.java:65)
at org.nick.program.main(program.java:304)

我的问题是导致nullpointer的原因是什么?我怎么能纠正它?

2 个答案:

答案 0 :(得分:5)

如果clazz不包含Object[]类型的任何私有字段(并且完全 Object[]!类型擦除可能会起作用,但继承不会t),fdarr都不会被设置。设置array_field的行假设如果未设置arr,则fd将是 - 但在刚才提到的情况下,它不会。

至于如何解决它...好吧,这取决于你究竟想要做什么。这段代码对我来说没什么意义,所以对应该做什么的描述会有很大的帮助。

答案 1 :(得分:1)

您的代码中有许多方法可能导致此NullPointerException

例如,在第5行:

field.getType().getCanonicalName().equals可能会导致此问题,因为getCanonicalName可能会返回null,在这种情况下最好的方法是使用: "java.lang.Object[]".equals(field.getType().getCanonicalName())

虽然这不是问题,但您必须使用如上所示的防御性编程(或至少检查nulls)。