文档章节

内核工具 – Sparse 简介

面码
 面码
发布于 2014/08/17 16:11
字数 1489
阅读 1493
收藏 10

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

sparse介绍

        Sparse 诞生于 2004 年, 是由linux之父开发的, 目的就是提供一个静态检查代码的工具, 从而减少linux内核的隐患.

其实在Sparse之前, 已经有了一个不错的代码静态检查工具("SWAT"), 只不过这个工具不是免费软件, 使用上有一些限制.

所以 linus 还是自己开发了一个静态检查工具.

具体可以参考这篇文章(2004年的文章了): Finding kernel problems automatically

Sparse相关的资料非常少, 关于它的使用方法我也是网上查找+自己实验得出来的.

内核代码中还有一个简略的关于 Sparse的说明文件: Documentation/sparse.txt

Sparse通过 gcc 的扩展属性 __attribute__ 以及自己定义的 __context__ 来对代码进行静态检查.

这些属性如下(尽量整理的,可能还有些不全的地方):

#define __bitwise    __attribute__((bitwise))     
确保变量是相同的位方式(比如 bit-endian, little-endiandeng)    
#define __user    __attribute__((noderef, address_space(1)))     
指针地址必须在用户地址空间    
#define __kernel    __attribute__((noderef, address_space(0)))     
指针地址必须在内核地址空间    
#define __iomem    __attribute__((noderef, address_space(2)))     
指针地址必须在设备地址空间    
#define __safe    __attribute__((safe))     
变量可以为空    
#define __force    __attribute__((force))     
变量可以进行强制转换    
#define __nocast    __attribute__((nocast))     
参数类型与实际参数类型必须一致    
#define __acquires(x)    __attribute__((context(x, 0, 1)))     
参数x 在执行前引用计数必须是0,执行后,引用计数必须为1    
#define __releases(x)    __attribute__((context(x, 1, 0)))     
与 __acquires(x) 相反    
#define __acquire(x)    __context__(x, 1)     
参数x 的引用计数 + 1    
#define __release(x)    __context__(x, -1)     
与 __acquire(x) 相反    
#define __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

Sparse 使用方法

__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;

 __user 的使用

如果使用了 __user 宏的指针不在用户地址空间初始化, 或者指向内核地址空间, 设备地址空间等等, Sparse会给出警告.

内核代码中的例子:

/*
 内核版本:v2.6.32.61  file:arch/score/kernel/signal.c 45行 
*/

static
 
int setup_sigcontext(structpt_regs *regs, struct sigcontext __user *sc)

 __kernel 的使用

如果使用了 __kernel 宏的指针不在内核地址空间初始化, 或者指向用户地址空间, 设备地址空间等等, Sparse会给出警告.

内核代码中的例子:

/*  内核版本:v2.6.32.61  file:arch/s390/lib/uaccess_pt.c 180行   
*/ memcpy(to, ( void __kernel __force *)  from , n);

__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)

__safe 的使用

使用了 __safe修饰的变量在使用前没有判断它是否为空(null), Sparse会给出警告.

我参考的内核版本(v2.6.32.61) 中的所有内核代码都没有使用 __safe, 估计可能是由于随着gcc版本的更新,

gcc已经会对这种情况给出警告, 所以没有必要用Sparse去检查了.

__force 的使用

使用了__force修饰的变量可以进行强制类型转换, 没有使用 __force修饰的变量进行强制类型转换时, Sparse会给出警告.

内核代码中的例子:

/* 内核版本:v2.6.32.61  file:arch/s390/lib/uaccess_pt.c 180行 */ 
memcpy(to, (void __kernel __force *) from, n);

__nocast 的使用

使用了__nocast修饰的参数的类型必须和实际传入的参数类型一致才行,否则Sparse会给出警告.

内核代码中的例子:

/* 内核版本:v2.6.32.61  file:fs/xfs/support/ktrace.c 55行 */
ktrace_alloc(int nentries, unsigned int __nocast sleep)

 __acquires __releases __acquire __release的使用

这4个宏都是和锁有关的, __acquires 和 __releases 必须成对使用, __acquire 和 __release 必须成对使用, 否则Sparse会给出警告.

__cond_lock 的使用

这个宏有点特别, 因为没有 __cond_unlock 之类的宏和它对应.

之所以有这个宏的原因可以参见: http://yarchive.net/comp/linux/sparse.html 最后一段.

这个宏的来源清楚了, 但是为什么这个宏里面还要调用一次 __acquire(x)? 我也不是很清楚, 在网上找了好久也没找到, 谁能指教的话非常感谢!!!

Sparse 在编译内核中的使用

用 Sparse 对内核进行静态分析非常简单.

# 检查所有内核代码
make C=1 检查所有重新编译的代码
make C=2 检查所有代码, 不管是不是被重新编译

补充

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;
}

本文转载自:http://www.cnblogs.com/wang_yb/p/3575039.html

面码
粉丝 26
博文 293
码字总数 72288
作品 0
成都
程序员
私信 提问
MySQL · 社区动态 · InnoDB Page Compression

背景:Punch hole和Sparse file Punch hole是一个需要操作系统和文件系统支持的特性,顾名思义就是在文件中打洞。这个特性的目的是为了减少数据文件的磁盘开销。比如一个大文件中有一部分数据...

阿里云RDS-数据库内核组
2015/08/02
0
0
6月9日上海 华东运维技术大会:演讲主题、演讲嘉宾等信息

会议名称:华东运维技术大会 参会形式:免费报名制(注释:须事先报名,场地有限) 会议定位:企业运维技术的最佳实践 会议主题:运维自动化、Web服务器的优化与架构、云计算、虚拟化技术 会...

金官丁
2012/05/19
2.6K
11
最佳75个安全工具介绍及其下载地址

最佳75个安全工具介绍及其下载地址 2010-10-01 19:37:56 标签:工具 下载 地址 休闲 职场 工具:Nessus(最好的开放源代码风险评估工具) 网址:http://www.nessus.org/ 类别:开放源码 平台...

yuanwx0328
2017/11/15
0
0
PostgreSQL深圳用户分会

主题: PG逻辑复制BDR、PGXC、PG RDS 主办: Postgres深圳用户会201501会(40人规模) 微信公众号:PostgresChina 官网:postgres.cn 承办:Postgres深圳分会 费用:免费(特别感谢宝华提供会议场...

YuanyuanL
2015/08/10
115
0
Tiny4412 ARM开发环境搭建—NFS网络根文件系统制作

Tiny4412从SD卡启动的简单网络文件系统制作 Tiny4412从SD卡启动的简单网络文件系统制作 1. 简介 嵌入式系统能够在开发板上正常运行,需要先进行系统配置,一个完整的嵌入式系统应该包含的几个...

u013738338
2017/01/21
0
0

没有更多内容

加载失败,请刷新页面

加载更多

x005-构造程序逻辑

构造程序逻辑 结合生活例子运用程序语言 百钱百鸡是我国古代数学家张丘建在《算经》一书中提出的数学问题:鸡翁一值钱五,鸡母一值钱三,鸡雏三值钱一。百钱买百鸡,问鸡翁、鸡母、鸡雏各几何...

伟大源于勇敢的开始
35分钟前
3
0
问题汇总

最近在补知识面的时候发现有几个问题, 第一个呢是 教程 没有提前准备好。(视频方面的吧 书上面的 都要有) 第二个呢是 ,开发工具太多了,搞不清楚到底用哪个了 和哪个教程相匹配。 第三个...

T型人才追梦者
今天
7
0
OSChina 周三乱弹 —— 我以前超喜欢晒太阳的

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @watergood :分享海先生的单曲《东篱》: 《东篱》- 海先生 手机党少年们想听歌,请使劲儿戳(这里) @xiaoshiyue :早.先喝几大碗鸡汤 @小小...

小小编辑
今天
18
1
法国电力项目二期正式验收

2019年12月10日, 法国电力项目二期正式验收. 二期实现了一个个人能源的自交易/自管理APP + 管理后台。 并就未来的合作技术方向进行了探讨: 去中心化数据存储/搜索引擎 可信计算/零知识证明...

怎当她临去时秋波那一转
今天
13
0
索引延迟关联

前言 今天在看代码的时候学习到了一种索引的优化,就先在此记录下来。 具体 举个例子,原sql如下: SELECT * FROM TABLE WHERE INDEX = '' LIMIT 10000, 10; 现象 就算INDEX用了查询索引,...

无敌小杰杰
今天
8
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部