Sparse¶
Sparse 是一个 C 程序语义检查器;它可以用来查找内核代码中一些潜在的问题。有关 sparse 的概述,请参阅 https://lwn.net/Articles/689907/;本文档包含一些特定于内核的 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” 的东西都会消失,最终对 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” 是特殊的。你可以使用常量零作为 bitwise 整数类型,而 sparse 永远不会抱怨。这是因为 “bitwise”(顾名思义)被设计用于确保 bitwise 类型不会混淆(小端 vs 大端 vs CPU 端 vs 其他),并且这里的常量 “0” 确实是特殊的。
使用 sparse 进行锁检查¶
以下宏在 gcc 中未定义,但在 sparse 运行时定义,以便使用 sparse 的 “context” 跟踪功能,应用于锁定。这些注解告诉 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__ 预处理器符号。