内核工具 – Sparse 简介
转载:http://www.cnblogs.com/wang_yb/p/3575039.html
Sparse是内核代码静态分析工具, 能够帮助我们找出代码中的隐患.
主要内容:
- Sparse 介绍
- Sparse 使用方法
- Sparse 在编译内核中的使用
- 补充
1. Sparse 介绍
Sparse 诞生于 2004 年, 是由linux之父开发的, 目的就是提供一个静态检查代码的工具, 从而减少linux内核的隐患.
其实在Sparse之前, 已经有了一个不错的代码静态检查工具("SWAT"), 只不过这个工具不是免费软件, 使用上有一些限制.
所以 linus 还是自己开发了一个静态检查工具.
具体可以参考这篇文章(2004年的文章了): Finding kernel problems automatically
Sparse相关的资料非常少, 关于它的使用方法我也是网上查找+自己实验得出来的.
内核代码中还有一个简略的关于 Sparse的说明文件: Documentation/sparse.txt
Sparse通过 gcc 的扩展属性 __attribute__ 以及自己定义的 __context__ 来对代码进行静态检查.
这些属性如下(尽量整理的,可能还有些不全的地方):
|
宏名称 |
宏定义 |
检查点 |
| __bitwise | __attribute__((bitwise)) | 确保变量是相同的位方式(比如 bit-endian, little-endiandeng) |
| __user | __attribute__((noderef, address_space(1))) | 指针地址必须在用户地址空间 |
| __kernel | __attribute__((noderef, address_space(0))) | 指针地址必须在内核地址空间 |
| __iomem | __attribute__((noderef, address_space(2))) | 指针地址必须在设备地址空间 |
| __safe | __attribute__((safe)) | 变量可以为空 |
| __force | __attribute__((force)) | 变量可以进行强制转换 |
| __nocast | __attribute__((nocast)) | 参数类型与实际参数类型必须一致 |
| __acquires(x) | __attribute__((context(x, 0, 1))) | 参数x 在执行前引用计数必须是0,执行后,引用计数必须为1 |
| __releases(x) | __attribute__((context(x, 1, 0))) | 与 __acquires(x) 相反 |
| __acquire(x) | __context__(x, 1) | 参数x 的引用计数 + 1 |
| __release(x) | __context__(x, -1) | 与 __acquire(x) 相反 |
| __cond_lock(x,c) | ((c) ? ({ __acquire(x); 1; }) : 0) | 参数c 不为0时,引用计数 + 1, 并返回1 |
其中 __acquires(x) 和 __releases(x), __acquire(x) 和 __release(x) 必须配对使用, 否则 Sparse 会给出警告
注: 在Fedora系统中通过 rpm 安装的 sparse 存在一个小bug.
即使用时会报出 error: unable to open ’stddef.h’ 的错误, 最好从自己源码编译安装 sparse.
参考: http://wangcong.org/blog/archives/504
2. Sparse 使用方法
2.1 __bitwise 的使用
主要作用就是确保内核使用的整数是在同样的位方式下.
在内核代码根目录下 grep -r '__bitwise', 会发现内核代码中很多地方都使用了这个宏.
对于使用了这个宏的变量, Sparse 会检查这个变量是否一直在同一种位方式(big-endian, little-endian或其他)下被使用,
如果此变量在多个位方式下被使用了, Sparse 会给出警告.
内核代码中的例子:
/* 内核版本:v2.6.32.61 file:include/sound/core.h 51行 */
typedef int __bitwise snd_device_type_t;
2.2 __user 的使用
如果使用了 __user 宏的指针不在用户地址空间初始化, 或者指向内核地址空间, 设备地址空间等等, Sparse会给出警告.
内核代码中的例子:
/* 内核版本:v2.6.32.61 file:arch/score/kernel/signal.c 45行 */
static int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
2.3 __kernel 的使用
如果使用了 __kernel 宏的指针不在内核地址空间初始化, 或者指向用户地址空间, 设备地址空间等等, Sparse会给出警告.
内核代码中的例子:
/* 内核版本:v2.6.32.61 file:arch/s390/lib/uaccess_pt.c 180行 */
memcpy(to, (void __kernel __force *) from, n);
2.4 __iomem 的使用
如果使用了 __iomem 宏的指针不在设备地址空间初始化, 或者指向用户地址空间, 内核地址空间等等, Sparse会给出警告.
内核代码中的例子:
/* 内核版本:v2.6.32.61 file:arch/microblaze/include/asm/io.h 22行 */
static inline unsigned char __raw_readb(const volatile void __iomem *addr)
2.5 __safe 的使用
使用了 __safe修饰的变量在使用前没有判断它是否为空(null), Sparse会给出警告.
我参考的内核版本(v2.6.32.61) 中的所有内核代码都没有使用 __safe, 估计可能是由于随着gcc版本的更新,
gcc已经会对这种情况给出警告, 所以没有必要用Sparse去检查了.
2.6 __force 的使用
使用了__force修饰的变量可以进行强制类型转换, 没有使用 __force修饰的变量进行强制类型转换时, Sparse会给出警告.
内核代码中的例子:
/* 内核版本:v2.6.32.61 file:arch/s390/lib/uaccess_pt.c 180行 */
memcpy(to, (void __kernel __force *) from, n);
2.7 __nocast 的使用
使用了__nocast修饰的参数的类型必须和实际传入的参数类型一致才行,否则Sparse会给出警告.
内核代码中的例子:
/* 内核版本:v2.6.32.61 file:fs/xfs/support/ktrace.c 55行 */
ktrace_alloc(int nentries, unsigned int __nocast sleep)
2.8 __acquires __releases __acquire __release的使用
这4个宏都是和锁有关的, __acquires 和 __releases 必须成对使用, __acquire 和 __release 必须成对使用, 否则Sparse会给出警告.
2.9 __cond_lock 的使用
这个宏有点特别, 因为没有 __cond_unlock 之类的宏和它对应.
之所以有这个宏的原因可以参见: http://yarchive.net/comp/linux/sparse.html 最后一段.
这个宏的来源清楚了, 但是为什么这个宏里面还要调用一次 __acquire(x)? 我也不是很清楚, 在网上找了好久也没找到, 谁能指教的话非常感谢!!!
3. Sparse 在编译内核中的使用
用 Sparse 对内核进行静态分析非常简单.
# 检查所有内核代码
make C= 检查所有重新编译的代码
make C= 检查所有代码, 不管是不是被重新编译
4. 补充
Sparse除了能够用在内核代码的静态分析上, 其实也可以用在一般的C语言程序中.
比如下面的小例子:

/******************************************************************************
* @file : sparse_test.c
* @author : wangyubin
* @date : Fri Feb 28 16:33:34 2014
*
* @brief : 测试 sparse 的各个检查点
* history : init
******************************************************************************/ #include <stdio.h> #define __acquire(x) __context__(x,1)
#define __release(x) __context__(x,-1) int main(int argc, char *argv[])
{
int lock = ;
__acquire(lock);
/* TODO something */
__release(lock); /* 注释掉这一句 sparse 就会报错 */
return ;
}

如果安装了 Sparse, 执行静态检查的命令如下:
$ sparse -a sparse_test.c
sparse_test.c::: warning: context imbalance in 'main' - wrong count at exit
Sparse相关资料可以参考wiki: Sparse wiki
内核工具 – Sparse 简介的更多相关文章
- 内核工具 – Sparse 简介【转】
转自:http://www.cnblogs.com/wang_yb/p/3575039.html Sparse是内核代码静态分析工具, 能够帮助我们找出代码中的隐患. 主要内容: Sparse 介绍 ...
- 部分GDAL工具功能简介
主要转自http://blog.csdn.net/liminlu0314?viewmode=contents 部分GDAL工具功能简介 gdalinfo.exe 显示GDAL支持的各种栅格文件的信息. ...
- Linux 内核引导选项简介
Linux 内核引导选项简介 作者:金步国 连接地址:http://www.jinbuguo.com/kernel/boot_parameters.html 参考参数:https://www.cnbl ...
- Linux-4.4-x86_64 内核配置选项简介【转】
转自:http://fx114.net/qa-188-150553.aspx 本篇文章主要介绍了"Linux-4.4-x86_64 内核配置选项简介",主要涉及到Linux-4.4 ...
- Linux内核分析(一)---linux体系简介|内核源码简介|内核配置编译安装
原文:Linux内核分析(一)---linux体系简介|内核源码简介|内核配置编译安装 Linux内核分析(一) 从本篇博文开始我将对linux内核进行学习和分析,整个过程必将十分艰辛,但我会坚持到底 ...
- Apache Jakarta Commons 工具集简介
Apache Jakarta Commons 工具集简介[转] Apache Commons包含了很多开源的工具,用于解决平时编程经常会遇到的问题,减少重复劳动.我选了一些比较常用的项目做简单介绍.文 ...
- nmon 及nmon analyser工具使用简介
nmon及nmon analyser工具使用简介 by:授客 QQ:1033553122 下载地址 http://nmon.sourceforge.net/pmwiki.php?n=Site.Down ...
- Postman Postman接口测试工具使用简介
Postman接口测试工具使用简介 by:授客 QQ:1033553122 本文主要是对Postman这个接口测试工具的使用做个简单的介绍,仅供参考. 插件安装 1)下载并安装chrome浏览器 2) ...
- Golang包管理工具glide简介
Golang包管理工具glide简介 前言 Golang是一个十分有趣,简洁而有力的开发语言,用来开发并发/并行程序是一件很愉快的事情.在这里我感受到了其中一些好处: 没有少了许多代码格式风格的争论, ...
随机推荐
- 简易nagios安装
这段时间一直在进行nagios安装的实验,进行了很多的实验,现在也就是将这些进行一些基础的记录. 本篇主要讲述的是进行nagios的简易安装,在安装完成之后,能够在web页面上看到本地的监控图像, n ...
- Python 代码性能优化技巧
选择了脚本语言就要忍受其速度,这句话在某种程度上说明了 python 作为脚本的一个不足之处,那就是执行效率和性能不够理想,特别是在 performance 较差的机器上,因此有必要进行一定的代码优化 ...
- bzoj 1014 [JSOI2008]火星人prefix(splay+hash)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1014 [题意] 给定一个字符串,要求提供修改一个字符,插入一个字符,查询两个后缀LCP ...
- codeforces 704B - Ant Man 贪心
codeforces 704B - Ant Man 贪心 题意:n个点,每个点有5个值,每次从一个点跳到另一个点,向左跳:abs(b.x-a.x)+a.ll+b.rr 向右跳:abs(b.x-a.x) ...
- Binder机制
在Android系统的Binder机制中,由一系统组件组成,分别是Client.Server.Service Manager和Binder驱动程序,其中Client.Server和Service Ma ...
- java 复习001
java 复习001 比较随意的记录下我的java复习笔记 ArrayList 内存扩展方法 分配一片更大的内存空间,复制原有的数据到新的内存中,让引用指向新的内存地址 ArrayList在内存不够时 ...
- [HIve - LanguageManual] Transform [没懂]
Transform/Map-Reduce Syntax SQL Standard Based Authorization Disallows TRANSFORM TRANSFORM Examples ...
- ubuntu安装hudson
因为hudson需要依赖java等,手动安装比较费劲 官方给出了一种很简单的解决方案:http://wiki.eclipse.org/Hudson-ci/Installing_Hudson_DEB s ...
- Phonegap学习点滴(2) -- 网络状态检测
Phonegap学习点滴(2) -- 网络状态检测 http://blog.csdn.net/x251808026/article/details/16992943 方法一:在MainActivit ...
- linux中vi编辑器
vi编辑器,通常称之为vi,是一种广泛存在于各种UNIX和Linux系 统中的文本编辑程序.它的功能十分强大,但是命令繁多,不容易掌握,它可以执行输出.删除.查找.替换.块操作等众多文本操作,而且用户 ...