根本工具 – Sparse 简介

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=1 检查所有重新编译的代码
make C=2 检查所有代码, 不管是不是被重新编译

 

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 = 1;
    __acquire(lock);
    /* TODO something */
    __release(lock);            /* 注释掉这一句 sparse 就会报错 */
    return 0;
}

 

假定设置了 Sparse, 执行静态检查的一声令下如下:

$ sparse -a sparse_test.c 
sparse_test.c:15:5: warning: context imbalance in 'main' - wrong count at exit

 

Sparse相关资料可参照wiki: Sparse
wiki