简体   繁体   English

空指针的原因

[英]Cause of nullpointer

Hello I have been trying to figure out this error for quite some time now. 您好,我已经尝试找出此错误已有相当一段时间了。 I'm having a newby problem with a nullpointer here is the class: 我在使用nullpointer遇到newby问题,这是该类:

Edit: The program is meant to inject code into another class to stop it from removing classes when it is loaded then it reflects the class files (stored as byte arrays) and then dumps to a class file. 编辑:该程序旨在将代码注入另一个类中,以防止其在加载时删除类,然后反映出类文件(存储为字节数组),然后转储到类文件中。

I have commented the line number that corresponds to the stack trace 我已经评论了与堆栈跟踪相对应的行号

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
}
}

Here is the stack trace: 这是堆栈跟踪:

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)

My question is what is causing the nullpointer and how could I correct it? 我的问题是什么导致空指针,我该如何纠正它?

If clazz doesn't contain any private fields of type Object[] (and exactly Object[] ! Type erasure may come into play, but inheritance doesn't), neither fd nor arr will be set. 如果clazz不包含任何类型为Object[]私有字段(并且完全是 Object[] !类型擦除可能会起作用,但是继承不会起作用),则不会设置fdarr The line that sets array_field assumes that if arr isn't set, fd will be -- but in the case just mentioned, it won't be. 设置array_field的行假定如果未设置arr ,则fd将为-但在上述情况下,则不会。

As for how to fix it...well, that depends on what exactly you're trying to do. 至于修复方法...嗯,这取决于您要尝试执行的操作。 The code doesn't make much sense to me at the moment, so a description of what it should be doing would help immensely. 目前,该代码对我而言意义不大,因此,对它应该做的事情的描述将大有帮助。

There's many methods in your code that may cause this NullPointerException . 您的代码中有很多方法都可能导致此NullPointerException

For example, at line 5: 例如,在第5行:

field.getType().getCanonicalName().equals may cause this problem as getCanonicalName may return null and best way in this case is to use: "java.lang.Object[]".equals(field.getType().getCanonicalName()) field.getType().getCanonicalName().equals可能会导致此问题,因为getCanonicalName可能返回null ,在这种情况下,最好的方法是使用: "java.lang.Object[]".equals(field.getType().getCanonicalName())

Although, this is not the problem, you have to use defensive programming as illustrated above (or at least check for nulls ). 尽管这不是问题,但您必须使用上述防御性编程(或至少检查nulls )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM