Sparse

Sparse 是 C 程序的语义检查器;它可用于查找内核代码中一些潜在的问题。请参阅https://lwn.net/Articles/689907/ 以获取 sparse 的概述;本文档包含一些内核特定的 sparse 信息。 有关 sparse 的更多信息,主要关于其内部结构,可以在其官方页面 https://sparse.docs.kernel.org 中找到。

使用 sparse 进行类型检查

“__bitwise” 是一个类型属性,所以你必须这样做

typedef int __bitwise pm_request_t;

enum pm_request {
        PM_SUSPEND = (__force pm_request_t) 1,
        PM_RESUME = (__force pm_request_t) 2
};

这使得 PM_SUSPEND 和 PM_RESUME 成为“bitwise”整数(“__force” 在这里是因为 sparse 会抱怨在 bitwise 类型之间进行转换,但在这种情况下我们确实 _想_ 强制转换)。并且因为枚举值都是相同的类型,所以现在 “enum pm_request” 也将是该类型。

对于 gcc,所有的 “__bitwise”/“__force stuff” 都消失了,并且对于 gcc 来说,所有这些最终看起来都像整数。

坦率地说,你不需要那里的枚举。 以上所有内容实际上都归结为一种特殊的 “int __bitwise” 类型。

所以更简单的方法就是这样做

typedef int __bitwise pm_request_t;

#define PM_SUSPEND ((__force pm_request_t) 1)
#define PM_RESUME ((__force pm_request_t) 2)

现在你已经拥有了严格类型检查所需的所有基础设施。

一个小提示:常数整数“0”很特别。 你可以使用常数零作为按位整数类型,而 sparse 永远不会抱怨。 这是因为 “bitwise”(顾名思义)旨在确保按位类型不会混淆(小端与大端与 cpu 端与任何东西),并且常量 “0” 确实 _是_ 特殊的。

使用 sparse 进行锁检查

以下宏对于 gcc 是未定义的,并在 sparse 运行时定义,以使用 sparse 的“上下文”跟踪功能,应用于锁机制。 这些注释告诉 sparse 何时持有锁,关于带注释的函数的入口和出口。

__must_hold - 在函数入口和出口时持有指定的锁。

__acquires - 在函数出口时持有指定的锁,但在入口时未持有。

__releases - 在函数入口时持有指定的锁,但在出口时未持有。

如果函数进入和退出时都没有持有锁,则以平衡的方式在函数内部获取和释放锁,则不需要任何注释。 上述三个注释用于 sparse 会报告上下文不平衡的情况。

获取 sparse

你可以从以下位置获取最新发布版本的 tarball:https://linuxkernel.org.cn/pub/software/devel/sparse/dist/

或者,你可以使用 git 克隆来获取 sparse 最新开发版本的快照

git://git.kernel.org/pub/scm/devel/sparse/sparse.git

一旦你有了它,只需做

make
make install

作为普通用户,它会将 sparse 安装到你的 ~/bin 目录中。

使用 sparse

使用 “make C=1” 进行内核 make,以便在所有重新编译的 C 文件上运行 sparse,或者使用 “make C=2” 在文件上运行 sparse,无论它们是否需要重新编译。 如果你已经构建了整个树,这是检查整个树的快速方法。

可选的 make 变量 CF 可用于将参数传递给 sparse。 构建系统自动将 -Wbitwise 传递给 sparse。

请注意,sparse 定义了 __CHECKER__ 预处理器符号。