静态代码分析(Static program analysis):在不运行程序的条件下,进行程序分析。
编译流程差不多分为这5个阶段:
- 词法分析生成token流
- 语法分析生成抽象语法树
- 针对抽象语法树进行语义分析,构建内部数据结构,如控制流图、生成中间代码
- 代码优化
- 目标代码生成
静态代码扫描通常分为两种:
模式匹配:匹配代码编译过程中的token流、抽象语法树(AST)和中间代码,根据经验认知某些样式的代码就是BUG
- 词法分析:词法分析是计算机科学中将字符序列转换为单词(Token)序列的过程。进行词法分析的程序或者函数叫作词法分析器,也叫扫描器(Scanner)。词法分析器一般以函数的形式存在,供语法分析器调用。词法分析阶段是编译过程的第一个阶段,是编译的基础。这个阶段的任务是从左到右一个字符一个字符地读入源程序,即对构成源程序的字符流进行扫描然后根据构词规则识别单词(也称单词符号或符号)。词法分析程序实现这个任务。词法分析是编译程序的必要阶段,核心任务是扫描、识别单词且对识别出的单词给出定性、定长的处理.cppcheck 是一个静态代码扫描工具,使用词法分析进行代码扫描,支持c、C++代码。主要对token流进行匹配,在扫描时无需编译,执行速度较快。
- 自动变量检查
- 数组的边界检查
- class类检查
- 过期的函数,废弃函数调用检查
- 异常内存使用,释放检查
- 内存泄漏检查,主要是通过内存引用指针
- 操作系统资源释放检查,中断,文件描述符等
- 异常STL函数使用检查
- 代码格式错误,以及性能因素检查
- 语法分析:语法分析是编译过程的一个逻辑阶段,主要任务是在词法分析的基础上将单词序列组合成各类语法短语,如程序、语句、表达式等等。语法分析程序判断程序在结构上是否正确。PMD是一个JAVA代码的代码错误分析工具,使用语法分析进行扫描。PMD可以支持扫描文件夹,查找文件夹下的".java"文件进行分析。主要原理是匹配抽象语法树。执行的检查包括:
- 潜在的bug:空的try/catch/finally/switch语句
- 未使用的代码:未使用的局部变量、参数、私有方法等
- 可选的代码:String/StringBuffer的滥用
- 复杂的表达式:不必须的if语句、可以使用while循环完成的for循环
- 重复的代码:拷贝/粘贴代码意味着拷贝/粘贴bugs
- 循环体创建新对象:尽量不要在for或while循环体内实例化一个新对象
- 资源关闭:Connect,Result,Statement等使用之后确保关闭掉
- 中间代码:中间代码是编译器编写者希望可以从语法树生成一个更接近目标代码的中间标识形式,或者使用这样一个中间表示代替语法树,然后再行这个新的中间表示生成目标代码。中间代码作为编译器前端和后端的桥梁,中间代码的作用是可使编译程序的结构在逻辑上更为简单明确,特别是可使目标代码的优化比较容易实现中间代码,即为中间语言程序,中间语言的复杂性介于源程序语言和机器语言之间。中间语言有多种形式,常见的有逆波兰记号、四元式、三元式和树。findbugs是一种开源分析Java代码错误的分析工具。findbugs的分析对象是java中间代码——字节码,因此在使用命令行调用工具的过程中,需要传入编译好的class文件或者jar包。同时,findbugs也发布多款的插件和图形界面,支持不同需求的用户。findbugs是目前java代码静态分析领域应用较广泛的工具。
- 未初始化参数,未初始化指针调用
- 除0错误
- 对于参数标记为nonnull的函数,调用时传入了可能为null的参数
- 对null指针进行解引用
- 无效栈地址(C)
- 未使用二元操作之后的值(C)
- 无效的数组大小(C)
- 不确定的数组下标访问(C)