前言

今天,又定位了一个令人懊恼的C++内存使用异常问题,最终结果,竟然是减少接口类的方法后,为了避免编译错误,顺手添加的强制类型转换导致的。
对于这样的问题,我们碰到很多很多次了。没有这样的问题,我们就不会有那么多的攻关,那么多的熬夜,进度也许不再那么捉摸不透......
我们有很多的抱怨,用的C/C++语言太底层,使用高级语言C#/JAVA等就不会有头痛的内存问题了,而且新的语言在很多方面提高了安全性,不会有那么多的陷阱。
我们有很多的理由,进度太紧,如果我们多点单元测试的时间,也许不会把这样的问题留到后面集成测试才发现;如果我们有一个安全编码的Checklist时刻提醒着,也许就会少犯一点错。
......   
再多的抱怨和理由,都不能解决问题。我们可以从这些问题去学到经验,去完善我们的Checklist;我们可以更加确信前期开发者测试的投入(包括TDD)在提高全流程效率方面的作用不可小视,从而加大前期的投入;但我们也需要一种手段,在必要的时候,帮我们排除一些错误,避免懊恼、沮丧的疑难问题定位,那就是静态/动态代码检查工具。(动态检查工具必须在能运行的情况下使用,所以先不考虑)
C/C++的静态检查工具主要有PC-lint、Coverity、Fortify等,后面两种都偏重量级,Coverity还需要提交结果到服务器,不便于随身携带、随时使用,PC-lint小巧方便,历史悠久,使用广泛,虽然被诟病为误报率高,但还是一个很有价值,值得随身携带的工具。特别是合理的配置选项减少误报之后,更是可以大幅提高查错、排错的效率。
PC-Lint9出来两年了,很早就听说它相比上一个版本改进非常大,可惜一直没发现可以下载试用的地方。今天居然发现了,于是迫不及待的下载试用了一回。

一、下载

csdn上可以找到下载地址:
http://d.download.csdn.net/down/2547212/flowlight
最新的patch可以到Gimpel官方网站下载:
http://www.gimpel.com/html/ptch90.htm

二、揭开PC-Lint9的神秘面纱

PC-lint9下载之后,主要的就是一个安装文件。安装过程也没什么特别,一路next安装下来,就在指定目录释放了lint相关的文件。
本以为进入lint安装目录会发现惊喜,结果出乎预料,跟8.0版本没什么区别,还是lint-nt.exe、和lnt目录,甚至里面的选项文件名也都没什么变化。我有点不敢相信自己的眼睛,命令行查询一下版本:
D:\PC-Lint9>lint-nt -v
PC-lint for C/C++ (NT) Vers. 9.00a, Copyright Gimpel Software 1985-2008
哦,看来还真是9.0版本,这个9.0版本跟8.0还是一脉相承的啊。

三、升级到最新版本

从官方网站下载最新的所有patch文件,解压缩到lint安装目录,然后写一个批处理依次patch就升级到了最新版本。
目录结构如下:
升级过程:
D:\PC-Lint9>update.bat

D:\PC-Lint9>PATCH.EXE LP9-A-B.RTP

D:\PC-Lint9>PATCH.EXE LP9-B-C.RTP

D:\PC-Lint9>PATCH.EXE LP9-C-D.RTP

D:\PC-Lint9>PATCH.EXE LP9-D-E.RTP

D:\PC-Lint9>PATCH.EXE LP9-E-F.RTP

D:\PC-Lint9>
D:\PC-Lint9>
D:\PC-Lint9>lint-nt -v
PC-lint for C/C++ (NT) Vers. 9.00f, Copyright Gimpel Software 1985-2010

整个升级过程与8.0也没有差异。

四、在线试用

发现PC-lint有个在线测试:On-Line Demonstration of FlexeLint and PC-lint (aka FlexeLint for Windows) 
http://www.gimpel-online.com/OnlineTesting.html
可以看到一些典型代码的lint检查结果,还可以修改代码再测试,也可以上传自己的代码检查。

五、若干例子

试用过在线之后也有在本地检查一遍的冲动,于是拷贝一段简单代码在本地运行。(代码参见:Simple Example (C++))
结果,PC-lint开始不断抱怨了。
首先是这段代码使用到string.h,找不到它在什么位置。
很简单,指定VC2008里面的string.h路径给它。
然后,PC-Lint又抱怨crtdefs.h中使用到的_WIN32、_MSC_VER没定义。
好说,它抱怨什么,我给什么,定义了这些宏。突然,我觉得有点不对劲啊,两次愚弄我了。
哦,我习惯于裸奔式的使用PC-lint了,从不借助官方根据不同编译环境已经配置的选项文件,因为之前我觉得只要知道lint原理,解决这些抱怨不成问题,而且所有选项在自己的控制中比较踏实,不用担心官方的选项干掉某个告警,从而漏掉了一个重要BUG。
该反省了,每次都费劲的配置选项以解决对我根本就没价值的抱怨,这次我很干脆的拿了co-msc90.lnt来用。果然好使,现在报告的告警全是我关心的了。
哦,原来PC-lint这样用可以更简单~~~~~~
附上我用的相关文件。
选项文件std.lnt:(第一个-i是指定co-msc90.lnt的路径)
-i"D:\PC-Lint9.0\lnt"
co-msc90.lnt

-i"C:\Program Files\Microsoft Visual Studio 9.0\VC\include"

用于测试的代码:
#include <string.h>

class X
{
int *p;
public:
X()
{ p = new int[20]; }
void init()
{ memset( p, 20, 'a' ); }
~X()
{ delete p; }
};

检查结果:(您可以仔细瞧瞧,起码这些问题都不是误报)
D:\Projects\Lab\PC-lint9-test\tests&gt;lint-nt std.lnt simple.cpp
PC-lint for C/C++ (NT) Vers. 9.00f, Copyright Gimpel Software 1985-2010

--- Module: simple.cpp (C++)
_
{ p = new int[20]; }
simple.cpp(8) : Info 1732: new in constructor for class 'X' which has no
assignment operator
simple.cpp(8) : Info 1733: new in constructor for class 'X' which has no copy
constructor
_
{ memset( p, 20, 'a' ); }
simple.cpp(10) : Warning 669: Possible data overrun for function 'memset(void
*, int, unsigned int)', argument 3 (size=97) exceeds argument 1 (size=80)
[Reference: file simple.cpp: lines 8, 10]
simple.cpp(8) : Info 831: Reference cited in prior message
simple.cpp(10) : Info 831: Reference cited in prior message
_
{ delete p; }
simple.cpp(12) : Warning 424: Inappropriate deallocation (delete) for 'new[]'
data

--- Wrap-up for Module: simple.cpp

Info 753: local class 'X' (line 3, file simple.cpp) not referenced
simple.cpp(3) : Info 830: Location cited in prior message

--- Global Wrap-up

Info 1714: Member function 'X::init(void)' (line 9, file simple.cpp) not
referenced
simple.cpp(9) : Info 830: Location cited in prior message

就这个简单例子来说,我们没有看到9.0版本新鲜的东西,只是我们看到了它在使用方法上几乎与8.0版本一样。同时,温故而知新,我们发现使用官方发布的配套选项文件可以使得配置变得简单。当然,这也许是地球人都知道的事实了:)
再看一个复杂点的例子:
检查初始化顺序问题。(代码参见:Multi Module Initialization and Redundancies)
D:\Projects\Lab\PC-lint9-test\tests\multimodule&gt;lint-nt std.lnt files.lnt
PC-lint for C/C++ (NT) Vers. 9.00f, Copyright Gimpel Software 1985-2010

--- Module: a.cpp (C++)

--- Module: b.cpp (C++)
           _
  int b = a;
b.cpp(3) : Warning 1544: Value of variable 'a' (line 4, file a.cpp)
    indeterminate (order of initialization)
a.cpp(4) : Info 830: Location cited in prior message

--- Global Wrap-up

对于这个例子,需要注意,它检查的是多个模块,在线检查有把多个模块写到一起的方式。实际使用中,是检查多个文件,就是把多个文件罗列在files.lnt中。
只能通过一个.lnt文件列出多个需检查的模块,才能起到模块检查的作用。运行多次命令是不行的,比如运行 lint-nt a.cpp  和lint-nt b.cpp,它是不能检查出模块间的问题的,lint根本不知道模块间是否有关联。
本来我以为,这个功能可能8.0版本没有吧,结果发现8.0也有这个功能。呵呵。
再看一个多线程竞争条件检查的例子:(代码参见:Multi-threading (C))
D:\Projects\Lab\PC-lint9-test\tests&gt;lint-nt multi-threading.cpp
PC-lint for C/C++ (NT) Vers. 8.00w, Copyright Gimpel Software 1985-2007

--- Module: multi-threading.cpp (C++)
_
//lint -sem( reader, thread )
multi-threading.cpp 6 Warning 425: 'unrecognized name' in processing semantic
'thread' at token 'thread'
_
//lint -sem( Lock::Lock, thread_lock )
multi-threading.cpp 7 Warning 425: 'unrecognized name' in processing semantic
'thread_lock' at token 'thread_lock'
_
//lint -sem( Lock::~Lock, thread_unlock )
multi-threading.cpp 8 Warning 425: 'unrecognized name' in processing semantic
'thread_unlock' at token 'thread_unlock'

D:\Projects\Lab\PC-lint9-test\tests&gt;
D:\Projects\Lab\PC-lint9-test\tests&gt;
D:\Projects\Lab\PC-lint9-test\tests&gt;set path=D:\Tools\CMD\Lint\SmartLint\PC-Lint9.0

D:\Projects\Lab\PC-lint9-test\tests&gt;lint-nt multi-threading.cpp
PC-lint for C/C++ (NT) Vers. 9.00f, Copyright Gimpel Software 1985-2010

--- Module: multi-threading.cpp (C++)

--- Thread messages:

Warning 457: Function 'h(void)' of thread 'main(void)' has an unprotected write
access to variable 'x' which is used by function 'h(void)' of thread
'reader(void)'
Warning 458: Function 'h(void)' of thread 'main(void)' has an unprotected read
access to variable 'y' which is modified by function 'g(void)' of thread
'reader(void)'

这回9.0版本没有令我们失望,根据上面8.0和9.0版本运行的比较可以看出,9.0版本支持-sem新的参数“thread、thread_lock、thread_unlock”,从而能够检查出未做多线程保护的一些问题。
当然,要检查这样的问题,是需要用-sem做些配置的。
其它例子:
1、强类型检查。(代码参见: Strong typedef Checking Example (C) 和 Dimensional Analysis (C++) )
typedef定义的类型,也进行检查。(C/C++本身不会进行检查的)
这在某些情况下还是非常有用。具体可参见代码。
2、互斥锁的误用检查。(代码参见:Mutual Exclusion (C))
包括:
(1)没有释放。
(2)释放没有与之匹配的加锁。
(3)多个分支有不同的加锁状态。

六、辅助工具

有很多PC-lint辅助工具,比如:
Cleanscape C++lint    更好的集成到Visual Studio。(收费软件)
Visual Lint from Riverblade  可以在写代码过程中默默的在背后执行lint,这可能对我们比较有帮助。(收费软件,这里可以下载试用http://bbs.pediy.com/showthread.php?p=660418,但经尝试Win7+VC2008不能启动,覆盖破解dll之后启动报错,不能显示Visual Lint插件)
更多辅助工具请参见:
http://www.gimpel.com/html/links.htm

七、PC-Lint9.0新增功能

最后,罗列一下PC-Lint9.0的一些新增功能。
完整列表请参见:http://www.gimpel.com/html/lint90.htm
1、线程分析,可以检查锁使用的正确性和可能缺少锁保护的变量。
2、通过预编译头大幅提升复杂项目的检查速度。
3、栈空间使用统计,可以汇总出单个应用的最大栈空间需求,只要程序中不存在递归并且是具有流程确定性的。
4、支持Deprecate声明。
5、可以针对一个(组)特定的符号开启某个检查项。易用性的很大改善,使得我们可以更好的运用一些提示级别的检查项。
6、“宏净化(Macro Scavenging)”。这个功能想必是为了解决PC-Lint与GCC不同版本配合中需要大量人工配置的尴尬局面吧。听起来不错的一个解决方案,具有较强的通用性。
7、新加入的“-sem”语法:成员方法的初始化/回收职能标识、inout类参数标识、多线程分析辅助标识…… 这一系列补充标识都是非常有实用价值的,尤其是前两项,解决了C++工程维护中扩充成员时经常碰到的忘记写配套的初始化或释放处理的顽疾。

八、参考资料

1、http://www.gimpel.com
2、PC-Lint终于迎来了9.0版本(http://blog.oasisfeng.com/2008/10/29/pclint-hits-v9/)

揭开PC-Lint9的神秘面纱相关推荐

  1. @程序员,为你揭开直播技术的神秘面纱!

    作者 | 阿文,责编 | 郭芮 头图 | CSDN 下载自视觉中国 出品 | CSDN(ID:CSDNnews) 随着Web 2.0 的普及以及移动互联网技术的发展,各种视频分享.流媒体直播类型的服务 ...

  2. 揭开人类语言的神秘面纱:从理解到处理自然语言

    https://www.toutiao.com/a6709740042509615619/ 随着人工智能的进步和技术变得越来越复杂,我们希望现有的概念能够接受这种变化或者改变自己.同样,在自然语言的计 ...

  3. 揭开webRTC媒体服务器的神秘面纱——WebRTC媒体服务器开源项目介绍

    揭开webRTC媒体服务器的神秘面纱--WebRTC媒体服务器&开源项目介绍 WebRTC生态系统是非常庞大的.当我第一次尝试理解WebRTC时,网络资源之多让人难以置信.本文针对webRTC ...

  4. 揭开Java 泛型类型擦除神秘面纱

    转载自   揭开Java 泛型类型擦除神秘面纱 泛型,一个孤独的守门者. 大家可能会有疑问,我为什么叫做泛型是一个守门者.这其实是我个人的看法而已,我的意思是说泛型没有其看起来那么深不可测,它并不神秘 ...

  5. .net单点登录demo_图文并茂,为你揭开“单点登录“的神秘面纱

    本文首发于政采云前端团队博客:图文并茂,为你揭开"单点登录"的神秘面纱 https://www.zoo.team/article/sso 概念 单点登录( Single Sign ...

  6. 小编带你一起揭开DLL木马的神秘面纱(转)

    在这个万"马"奔腾的时代,网络上充斥着各种各样的木马,不过随着杀毒技术的进步和大家防毒意识的提高,传统木马已渐渐失去市场,而DLL木马则"与时俱进"以其强大的生 ...

  7. 【第3期】量化大咖来了!揭开量化对冲的神秘面纱

    阅读原文:http://club.jr.jd.com/quant/topic/1368799 京东金融官方资讯QQ群:456448095 有什么想咨询的都可以来询问我们 我们期待已久的第3位量化大咖来 ...

  8. 揭开均线系统的神秘面纱_揭开依赖注入的神秘面纱,并通过此快速介绍了解它的实际应用...

    揭开均线系统的神秘面纱 by Sankalp Bhatia 通过Sankalp Bhatia 揭开依赖注入的神秘面纱,并通过此快速介绍了解它的实际应用 (Demystify Dependency In ...

  9. 揭开均线系统的神秘面纱_在应用程式审查API中揭开新玩法的神秘面纱

    揭开均线系统的神秘面纱 During the #11WeeksOfAndroid the new Play In-App Review API was announced. This was a lo ...

  10. html5实现单点登录,图文并茂,为你揭开“单点登录“的神秘面纱

    概念 单点登录( Single Sign On ,简称 SSO),是目前比较流行的企业业务整合的解决方案之一,用于多个应用系统间,用户只需要登录一次就可以访问所有相互信任的应用系统. 前置介绍 同源策 ...

最新文章

  1. MySQL数据库使用连接更新表中某个字段数据
  2. LaTeX文档插入图片的几种常用方法
  3. 第一行代码学习笔记第八章——运用手机多媒体
  4. 牛客 - 阶乘(唯一分解定理)
  5. 静态html引入js添加随机数后缀防止缓存
  6. window server2008 r2
  7. jep290涉及jdk版本_JDK 14 – JEP 361从预览中切换表达式
  8. c语言bfs程序讲解,面试算法--二叉树DFS/BFS实现(C语言)
  9. GCC中的弱符号与强符号
  10. WinForm 快捷键设置
  11. ServHa双机热备简单配置
  12. 如何向Mac Dictionary App添加其他语言
  13. k8s部署jenkins
  14. 【提问】iOS UIAtumator 是怎么判断元素isVisible的?
  15. 问题解决办法:pip tensorrt成功,PyCharm import出错
  16. javase和java区别_javase和java有什么区别
  17. hr面试性格测试30题_网友应聘华为表现优秀,最终却挂在性格测试上,看真题我哭……...
  18. java excel公式计算_java中Excel公式的计算和函数,实例展示
  19. Sql语句区分中英文
  20. 拆书帮便签读书法,重新定义高效阅读

热门文章

  1. vue获取麦克风_vue使用recorder.js实现录音功能
  2. 使用 json-server 作为 mock 数据
  3. 你了解node多进程吗
  4. 导出一条数据_来自小师弟的灵魂拷问之数据泵导出丢失的那些数据量去哪了?...
  5. qt 获取用户缩放_Qt-如何创建随窗口缩放并保持纵横比的图像?
  6. 腾讯云服务器CentOs7系统发布个人网站
  7. 20190824:(leetcode习题)报数
  8. 简述python3默认使用的编码标准_Python3.X默认使用的编码是
  9. ajax 实时进度_【乐建工程宝】如何把控施工项目进度
  10. vb中SendMessage函数