烩:遇上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。