如何调试库代码中发生的 NullPointerException?

Posted

技术标签:

【中文标题】如何调试库代码中发生的 NullPointerException?【英文标题】:How to debug NullPointerException occurred in library code? 【发布时间】:2013-02-21 02:33:50 【问题描述】:

我正在用 java 解压一个 ZIP 文件:

ZipFile zipFile = new ZipFile(theZipFile);
  Enumeration<? extends ZipEntry> zipEntries = zipFile.entries();
    while(zipEntries.hasMoreElements())
      ZipEntry entry = zipEntries.nextElement(); /// <---Nullpointer exception happens here
  

代码执行超过while(zipEntries.hasMoreElements()),但未能提取 ZipEntry。

奇怪的是hasMoreElements返回true,但是尝试取出元素时出现空指针。

异常来自 JDK lib 的 ZipFile 类,我在调试器中看不到局部变量,那么如何找出 Zip 文件的问题?

编辑: 堆栈跟踪:

java.lang.NullPointerException
    at java.util.zip.ZipFile.getZipEntry(ZipFile.java:529)
    at java.util.zip.ZipFile.access$900(ZipFile.java:56)
    at java.util.zip.ZipFile$1.nextElement(ZipFile.java:511)
    at java.util.zip.ZipFile$1.nextElement(ZipFile.java:481)

【问题讨论】:

请发布堆栈跟踪。另外,在您处理文件时是否有可能修改文件? 如果你附加了一个调试器,你检查过 zipEntries 的值吗?检查 zipEntries 上的元素怎么样? @TedHopp 堆栈跟踪已添加。不,文件在解压过程中没有被修改。 这是整个堆栈跟踪吗?那里没有你的代码。 @TedHopp 从我的帖子ZipEntry entry = zipEntries.nextElement()的这一行开始 【参考方案1】:

这里是 getZipEntry 方法(截至 1.7.0_10):

private ZipEntry getZipEntry(String name, long jzentry) 
    ZipEntry e = new ZipEntry();
    e.flag = getEntryFlag(jzentry);  // get the flag first
    if (name != null) 
        e.name = name;
     else 
        byte[] bname = getEntryBytes(jzentry, JZENTRY_NAME);
        if (!zc.isUTF8() && (e.flag & EFS) != 0) 
            e.name = zc.toStringUTF8(bname, bname.length);
         else 
            e.name = zc.toString(bname, bname.length);      // Line 529
        
    
    /* snip */
    return e;

NullPointerException 被抛出该行的唯一原因是 ezcbnamenull

e 不能是null,因为在这个方法中明确实例化了。

zc不能是null

public ZipFile(File file, int mode, Charset charset) throws IOException

    /* snip */
    this.zc = ZipCoder.get(charset);
    /* snip */


static ZipCoder get(Charset charset) 
    return new ZipCoder(charset);

这意味着bname 必须是null,这将很难调试。 getEntryBytesnative 方法:

private static native byte[] getEntryBytes(long jzentry, int type);

这就是我将如何进行:

确定是那个特定的 zip 文件还是所有的 zip 文件。如果是那个特定的 zip 文件,请尝试重新制作它。 更新您的 Java 版本,getEntryBytes 可能存在已修复的错误 向 Oracle 提交错误报告

【讨论】:

好的,终于搞定了。 ZipFile 有一个名称为空字符串的条目!感谢杰弗里的详细解释! 这应该最终用 JDK9 (bugs.openjdk.java.net/browse/JDK-8048990) 解决。【参考方案2】:

我最近遇到了同样的问题,所以我比较了JDK 1.61.7相关的zip源代码

真正的原因jdk 1.6将由constructorjzentry初始化zipEntry > 像这样:

ZipEntry ze = new ZipEntry(jzentry);

ZipEntry(long jzentry) 
    initFields(jzentry);

但是在jdk 1.7中我们可以看到它使用

private ZipEntry getZipEntry(String name, long jzentry) 
    ZipEntry e = new ZipEntry(); // it did not use jzentry initial it

当某些 jar 文件有 empty entry 时,它会抛出异常。

【讨论】:

以上是关于如何调试库代码中发生的 NullPointerException?的主要内容,如果未能解决你的问题,请参考以下文章

SpringDataForCassandra:当数据库中的 Int 列设置为空时,实体中的 NullPointerEx

如何查看和调试动态链接库的内存泄露

如何在 Xcode 5 中调试库?

如何使用断点调试SwiftUI代码库?

Failed to start bean ‘documentationPluginsBootstrapper‘; nested exception is java.lang.NullPointerEx

需要在 GDB 中加载共享库的调试符号