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__ 预处理器符号。