2012-02-11 95 views
2

你好,我一直试图弄清楚这个错误很长一段时间了。我有一个空指针newby问题这里是类:空指针的原因

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

我评论说,对应于堆栈跟踪

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) 

我的问题是什么原因造成的空指针,我怎么能改正?

+0

如果您在此处包含堆栈跟踪,它也会有所帮助。 – 2012-02-11 18:56:57

+0

你可以显示堆栈跟踪吗? – 2012-02-11 18:57:24

+0

如果您发布完整的异常堆栈跟踪,您也可以轻松进行调试。 – span 2012-02-11 18:57:32

回答

5

如果clazz不包含Object[]类型的任何私有字段(和正是Object[]!类型擦除可能会发挥作用,但继承并不),既不fd也不arr将被设置。设定为array_field的行假设如果arr未设置,fd将会 - 但在刚刚提到的情况下,它不会。

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

+0

感谢您的迅速响应我已更新我的线程,尝试并提供一些更多信息:) – Nicholas 2012-02-11 19:50:17

+0

@Nicholas:我的意思是,getObjects应该做什么?显然不只是获得物体。 – cHao 2012-02-11 19:52:38

+0

搜索每种返回类型类的方法 – Nicholas 2012-02-11 20:01:25

1

代码中有很多方法可能会导致此问题NullPointerException

例如,在第5行:

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

尽管,这不是问题,你必须:

  1. 使用如上所示的防御性编程。 (或至少检查 的nulls
  2. 提供我们的堆栈,以便我们可以帮助你。
+0

该类显然是按名称加载的,所以它几乎必须有一个规范名称。 – cHao 2012-02-11 19:22:26

+0

我同意你的看法,我只想告诉他他必须防御他自己的程序(我已经编辑了我的答案) – 2012-02-11 21:06:45