烩:遇上 Assert、空指针异常

前段时间装 Gentoo 用 parted 分区时,执行“name 1 grub”时遇上 assert 报错:

1.png

一条经验:

遇到空指针、assert 错误、NullPointerException,诸如此类,均属意外错误。

这类错误太广,遇到后我建议先下载最新版本或者拉最新代码来编译,确认 bug 是否修复。如果没有修复,再用 Google 搜索,如能从 Google 搜索到邮件列表归档或者 issue 列表相应主题,说明有人提交 bug 了,可以持续关注处理进展。

前面两步都失败,就只有看源码了。

恰好这个 parted 的 bug 当时没有找到相关信息,最新源码中也存在问题。根据异常信息,定位到报错点:

PedPartition*
ped_disk_get_partition (const PedDisk* disk, int num)
{
        PedPartition*   walk;

        PED_ASSERT (disk != NULL); // 触发点在这里

        for (walk = disk->part_list; walk;
             walk = ped_disk_next_partition (disk, walk)) {
                if (walk->num == num && !(walk->type & PED_PARTITION_FREESPACE))
                        return walk;
        }

        return NULL;
}

disk 参数指向分区信息,所以产生 bug 的原因是我忘记对新磁盘进行分区,这也是没认真看手册导致的——也说明不按流程来可能会意外收获漏洞或者 bug。

虽然 bug 已定位出来,但我还是给官方提交了一个 patch 过去,patch 很简单,如果 disk 为 NULL 就打印提示信息并 return:

--- a/libparted/disk.c
+++ b/libparted/disk.c
@@ -1594,7 +1594,10 @@ ped_disk_get_partition (const PedDisk* disk, int num)
 {
        PedPartition*   walk;

-       PED_ASSERT (disk != NULL);
+        if (disk == NULL) {
+          fprintf(stderr, "you must specify partition.");
+          return NULL;
+        }

        for (walk = disk->part_list; walk;
             walk = ped_disk_next_partition (disk, walk)) {

但是我犯了一个错,提 patch 时没关注 parted 架构,parted 底层操作是调用 libparted 库完成的,disk.c 来自 libparted 目录。因此这里用 assert 本没有错,错的是 parted 本身没处理 NULL 的情况,而不是库的问题。

库函数不要屏蔽错误细节,把错误细节暴露给调用端。

所以开发者回复我:

The patch is not correct because as a library, libparted can not
simply write directly to stderr; it must throw an exception instead.
In all probability the bug lies in parted itself, which should not be
calling ped_disk_get_partition on a NULL disk pointer.  I'll work on a
proper fix for this.

最后官方再次回复说已经有人修正了这个 bug:

It seems this was already fixed:

 commit f5c628dd51c7d77ff939554425159ab6e8aef1c0
 Author: Brian C. Lane <[email protected]>
 Date:   Mon Jul 13 16:43:11 2015 -0700

     parted: Fix crash with name command and no disklabel (#1226067)

     A typo (the last I think) from commit 7eac058 wasn't properly
checking
     the result of ped_disk_new so it could crash if there was no
disklabel
     on the device.

剩下的就是等 Gentoo 更新,或者自己手动更新有 bug 的软件。