基于编译器的静态代码分析与软件开发效率、质量和性能

基于编译器的静态代码分析与软件开发效率、质量和性能

本文节选自《基础软件之路:企业级实践及开源之路》一书,该书集结了中国几乎所有主流基础软件企业的实践案例,由 28 位知名专家共同编写,系统剖析了基础软件发展趋势、四大基础软件(数据库、操作系统、编程语言与中间件)的领域难题与行业实践以及开源战略、生态建设与人才培养。

1 作者介绍

李隆: 目前担任鉴释科技的首席科学家,专注于代码验证基 础架构的研发。于 2008 年在中国科学技术大学获得计算机软件和理论博士学位,专门研究基于编程语言的理论、技术在构建高效、可靠软件方面的应用,并发表了数篇期刊和会议论文。毕业后,加入了三星电子,在先行技术小组从事统计机器翻译的研发工作。于 2010 年加入 HP 编译器团队,从事 HP Non-Stop 服务器 编译器后端及工具链的研发工作。

注:本文整理自李隆博士在 DIVE 全球基础软件创新大会 (2022)上的演讲,由李冬梅整理

图片

随着软件规模不断增大,架构日益复杂,在软件开发过程 中兼顾开发效率、软件质量和软件性能越来越困难。为了追求更 高的开发效率和更短的交付周期,软件质量和性能往往成为被忽 视甚至牺牲的对象,给软件开发带来长期损害。静态分析是指 在不实际运行程序的前提下,利用编译器技术中的词法 / 语法分 析、控制流 / 数据流 / 别名 / 上下文分析建立代码的静态视图,在 此基础上应用各种检查逻辑和规则来确定程序中影响软件质量和性能的问题代码。通过静态代码分析工具与 DevOps 流程紧密结合、 CI(Continuous Integration,持续集成)/CD(Continuous Delivery,持续交付)集成和扫描差分报告,在编码过程中实施编码规范和惯用法检查,结合预定义和自定义规则的语义和业务逻 辑检查,实现更高的开发效率、更好的软件质量和软件性能。

下面主要从四部分展开,分别是静态分析工具在当前软件开发流程中的应用、编译相关技术在静态分析工具中的应用、编译 相关技术在提升软件质量和性能上的更多应用以及未来展望。

一、 静态分析工具在当前软件开发流程中的应用

静态分析工具(SAST)在不运行程序的情况下进行源代码、代码中间表示,甚至二进制代码上的分析。这种方式用于发现程序中的潜在漏洞并及早修改,从而使发布的程序更安全、更可靠。静态分析也可以用于程序优化,提升程序性能。后者通常由编译器自动完成,无须开发人员参与。

一个完整的软件开发生命周期遵循需求分析→详细设计→代码实现→测试→客户端部署→维护的流程,如图 4-2-1 所示。程序在正式交付之后,根据客户的实际需求还会做相关的调整,并 继续迭代。静态分析不仅可以在代码实现、测试环节,甚至在程序部署环节都能发挥一定作用。

https://mmbiz.qpic.cn/sz_mmbiz_png/4FyZUGcnoOs95cPTa3JviaD6IhGUvs0YkMXMPDN3pJmEyv2fgh4jI9x3D6hNng4KOVz9jic9iamqn5RicZUGgeGcicw/640?wx_fmt=png&from=appmsg&wxfrom=5&wx_lazy=1&wx_co=1

图 4-2-1 完整的软件开发生命周期

我们为什么要强调在软件开发生命周期中应用静态分析?根据IBM的统计数据,开发阶段的修复缺陷的相对成本最低,在测试和产品发布后修复缺陷的相对成本将会大幅增长,如图 4-2-2 所示。

在这里插入图片描述

图 4-2-2 修复缺陷的相对成本

注意:修复在开发过程中发现的错误会致使成本提高6.5%,而修复在测试阶段发现的错误则致使成本提高15%,产品发布后 修复错误会致使成本提高100%。

另一份报告中则指出,缺陷修复成本是随着周期的推移而逐渐增高的,代码缺陷数量大多出现在开发阶段。但是实际的缺陷修复大部分都在较为靠后、成本相对较高的阶段。通过静态代码分析工具,我们可以在较早期,也就是开发阶段找到缺陷。在此时修复缺陷不仅可以提高程序的安全性和可靠性,而且可以极大地节约成本。这也就是为什么目前静态分析愈发重要,也愈发被各个开发厂商所强调。

二、 编译相关技术在静态分析工具中的应用

开发人员在代码编写阶段可能更熟悉代码的自动补全。这是一个几乎所有IDE上都有的简单功能,能够极大地提升开发人员的编写效率,如图 4-2-3 所示。

在这里插入图片描述

图 4-2-3 代码自动补全

另一种开发人员熟悉的功能则是编码规范的检测。像是 MISRA 之类的规则集中虽然包含很多编码规范相关内容,但是检测其实也可以放在 CI/CD 的流程中。在软件开发生命周期流程中, CI/CD 可以进行各种漏洞和规则的检测,如检测常见的空指针引用或使用未初始化变量等漏洞,以及检测 CERT 、OWASP、 CWE 、CVE 等规则集下的合规性。

此外,软件成分分析也可以在CI/CD 中进行。软件成分分析工具主要用于检测所提交代码中许可证的合规性。目前虽然开源软件资源丰富,但如果不留心授权问题,就很可能导致风险,甚至面临法律问题。另外,软件成分分析还可以针对第三方软件中的已知漏洞给予提示,并提供更完整的信息作为参考,这对是否使用该第三方软件具有决定作用。很多开源软件库虽然强大,但我们真正用到的只是其中一小部分,软件成分分析工具能帮助我们做出更好的判断和选择。在部署阶段,静态分析工具还可以对二进制代码、字节码进行检测。它们是代码真正部署到客户端前,静态分析工具可以做的最后尝试,这类应用的需求虽然存在,但并不广泛。

这些静态分析工具中用到了哪些技术呢?

1. 静态编辑工具背后的支撑技术

代码自动补全功能主要用到了计算机编译中的词法、语法分析。编码规范不仅囊括了语法、词法分析,还需要在抽象语法树上通过模式匹配,查找并就代码中与规范相违背的部分给出警告。这些在编译中都应算作前端的技术内容。

编码规范的检测大部分情况下只能覆盖较为简单的前端规则,要检验稍微复杂的规则或漏洞则不仅要处理抽象语法树,还需要对代码中间表示,甚至是二进制代码进行模式匹配。

然而,语法、词法上的模式匹配有其局限性。若一款静态分析工具要处理更深层次的问题,则还应在代码中间表示上进行语义分析,并利用编译中的“符号执行”技术。可以说,在语法层面和语义层面进行双重模式匹配,基本可以覆盖一个程序在静态分析阶段所能处理的所有问题场景。

对于软件成分分析来说,目前绝大多数工具都只是将代码 以文本的形式加以处理,基于文本特征值进行相似度的计算。因此,这一类工具的准确度和有效性还不是十分理想。

2. 静态分析工具的衡量指标

我们要如何衡量一款静态分析工具的好坏呢?对于用户来说,最直观的感受无非是准确率和资源消耗。

(1)准确率

影响准确率的因素可以分为误报率和漏报率。误报是指分析工具错误地将正确代码报错的情况,漏报则是指分析工具没能找 出代码中的问题。用户在工具的使用过程中通常对漏报无感,因为他并不知道代码中还有什么问题没有找出来;大多数用户更在意的是分析工具的误报率。当然,现在也有很多测试集可以体现分析工具的漏报情况,但这些测试集所覆盖的范围也都非常有限。若要提升准确率,静态分析工具应能处理以下技术内容:

1)上下文敏感。如果一款工具可以完整、正确地构建函数之间的调用关系图,那么它就可以更好地处理带有上下文、跨函数、跨文件的分析。

2)流敏感。工具要能够处理好控制流图以及静态单赋值情况。

3)跨维度分析。工具要能够处理跨函数、跨文件,甚至是跨语言的分析。

这三项技术内容决定了一款分析工具在准确度指标上的表现是否优秀。

(2)资源消耗

用户平时感触最深的就是响应时间和成本。响应时间是指用户希望分析工具可以快速检测出问题并返回结果,而不必期间先去处理其他事务再回来看结果。成本则是对用户财力的考量,如果用户需要采购大量服务器以支撑分析工具,那么成本将会非常高昂。

3. 用户自定义规则

目前也有静态分析工具的开发厂商提供二次开发功能。这是因为不同的用户,其需求也不同。静态分析工具的开发厂商不可能做到全面覆盖所有用户的所有需求。针对这种情况,有两种解决方案。一是工具开发厂商根据用户需求进行开发,但用户需要承担高昂的开发成本。二是工具开发厂商预留二次开发功能,让用户根据自身需求对分析工具进行二次开发。针对二次开发的需求,静态分析工具需要具备基于符号执行的语义分析的能力,通过动态链接的形式,允许用户自行开发的规则按需链接到工具的扫描引擎中。

4. 第三方库的分析

大多数用户在使用第三方库时,对库中API 的设计难以有完美的理解,这也就意味着在库的实际使用过程中会产生分歧。常见的使用第三方库出现的问题,大多是由于用户对库的调用与其真实的语义之间存在差异。因此,用户希望工具的开发厂商能够 给出类似C库的标注以减少歧义,或提供类似二次开发的功能,以便能够自行完成对第三方库的分析标注,从而真正将链接的第三方代码包含到分析中来。

三、 编译相关技术在提升软件质量和性能上的更多应用

编译技术还可以提升软件的性能,在编译中又称编译优化。其使用场景包含并不限于以下方面:

1)公共子表达式删除:通过减少程序执行的指令数目来提高程序性能。

2)函数内联(inline):通过减少调用消耗,来提升性能。

3)死代码删除:主要针对代码规模的优化。

比如,在 MISRA 规则集中有这样一条规定,程序中不应存在死代码。比如下面这个例子—foo()。

void foo() {
…
if (1) {
…
} else {
…
}
}

因为if 的条件是永真的,所以永远都不会走else的分支,在编译优化中,编译器可能会将全部else 分支,甚至if 的判断语句 全部删除。但MISRA规则集只会提示我们有一段代码不会被执行。那么大家可能会问,既然编译优化已经能够将死代码删除,为什么我们还需要 MISRA 这样的规则集去进行检测呢?在实践中,死代码的出现可能是历史原因造成的,如长期的开发、版本 迭代后,会遗留一些不明所以的东西在代码中;死代码的出现也 可能是由于写代码的人当时出现了思维误差,或是手误,else 分支的执行需求确实存在,但因为思路或想法不够完整,所以条件 语句中的表达式变成了永真值。这样的报错提示也可以促使软件开发者仔细思考这个判断条件中到底应该写什么,到底需要处理什么样的场景。简单删除死代码,虽然对程序执行没有影响,但却可能导致功能上的缺失。

1. 编译优化对静态分析工具的影响

编译优化不仅与静态代码中的规则检测和优化有关,而且会影响静态分析工具。对基于编译优化的静态分析工具而言,可以被编译优化掉的 代码错误是不会被工具检测到的。以下面一段代码为例,虽然变量x不会被使用,但在第三行有一个除以零的错误。在真正运行时,因为变量 x 已经被优化掉了,所以绝大部分编译器都不会运行到除以零的这行,也就不会执行 1 除以 0 的操作。但对静态分析工具而言,如果没有考虑到优化的内容,那么这里还是会报出除以零的错,当然这里的代码也是一段死代码。

int foo(){
int x;
x = 1/0;
return 0;
}

函数内联对静态分析工具也有极大的影响。如前文所讲,一款工具的准确度在很大程度上取决于其能否正确处理上下文信息,而函数内联是能够帮助分析工具最完整地获得上下文信息的 手段。函数内联也会造成函数规模变大,导致分析工具所要占用的内存和时间直线上升。编译优化所做内联会在代码大小、代码效率和执行速度间寻找一个平衡点,但这也就造成了静态分析工具的一个能力缺陷。对依赖函数内联的静态分析工具而言,函数内联的层数就是其上下文分析的准确度的极限,对更深层次调用 的分析将不再准确,误报率、漏报率都会明显上升。

2. 更进一步地提升性能

为进一步提升程序性能,编译器还可以基于反馈进行优化。通过部署到实际运行环境中代码内的插桩进行数据收集,编译器以这些数据为参考,再重新进行优化。较为常见的应用有分支预测,只有在实际环境中运行了足够长的时间后,我们才能准确知道哪些分支被执行的次数较少,从而让编译器在做程序优化时,将执行次数较少的分支作为一个跳转的目标,以实现在下次部署 时达到更好的性能。在DAST(动态代码分析工具,可以测试Web、移动和 API 应用程序,通过模拟攻击来发现漏洞/ 安全漏洞,结合自动扫描仪或手动渗透测试实践来实时测试应用程序)或 IAST(交互式自动代码分析工具,可在应用和API 中自动识别和诊断软件漏洞)中,插桩也可协助提升软件质量。举例来说,如果程序没有进行空指针或数组越界的检查,那么编译器可以在程序进行指针的解引用、数组下标访问等危险操作前直接插入检查和纠错的代码, 同时收集部署运行时的数据并反馈给开发者,让开发者判断是否需要进行相应的修改。发生指针解引用为空或数组访问越界的情况的原因,除了开发者在编写代码时有疏漏外,还有可能是开发者在对数据逻辑进行假设时出现了问题。这样的信息对开发者而言也是有用的。

3. 静态分析工具现状

我们来看下静态分析工具的应用现状。比如:在代码编写时,开发者会用到集成在 IDE 中的代码补全、语法高亮等功能;软件开发商也会广泛使用 CI/CD 流程中的漏洞检测、规范规则检测。 但后者的检测结果往往得不到开发者的重视。原因有二:一是目前静态分析工具的误报率仍然偏高;二是历史遗留问题,开发者在接手一段代码后通常不会有兴趣去研究或修改前人编写的代码。这并不稀奇,我们都知道看别人写的代码很不容易。

因此,我们现在更强调分析工具的增量扫描结果。以谷歌发布的结果中可以看出,通过强调单次代码提交在原有基准线上新引入缺陷和漏洞的增量式报告,开发者会更有动力、更积极地进行代码修复,因为开发者仍在关注当前问题,所以修复的速度也很快。总的来说,在开发过程中强调增量扫描,是软件开发过程中更好的选择。

四、 未来展望

这些年来,随着AI 技术的愈发火热,不少人尝试在静态分析工具中加入AI 相关的技术以分析缺陷和漏洞。但目前仍未有强有力的数据可以说服厂商或开发人员使用AI 技术替代当前的静态分析工具。

另外,目前大多数静态分析工具所依赖的仍然是编译中的前端技术,这也就意味着还有很多中间优化技术以及后端深层次技术没能很好地引入静态分析工具中来。利用这些已有的、成熟的 编译技术进一步完善静态分析工具,也是一个非常可行的发展方向。但许多大厂由于所处的市场地位,在对已有成熟工具进行大规模修改时难免遇上很大困难。

我个人认为,未来软件成分分析之类的工具可以考虑将程序特征加入分析的特征值中,而不是现在这样单纯基于纯文本做分析。

目前软件成分分析工具所面临的一个大问题就是,如果我们 将程序中的关键字加以替换,那么基于纯文本的分析工具所计算出的特征值将会有很大差异。这也就是说,如果我们简单地进行足够次数的全局替换,分析工具将无法识别程序中抄来的代码和有版权约束的开源代码之间有什么差别。但如果开源方认真查看这些全局替换的代码,会很容易地发现抄袭。

图书推荐

随着云计算和生成式 AI 的逐渐发展,基础软件的技术栈也在发生变化,市场现存的基础软件领域的图书相对较少,且多数最近两年没有更新。但是,基础软件领域已经发生了巨大变化,我们现在所讲的基础软件是以云、AI 为底座的基础软件,这些新的变化都可以在**《基础软件之路:企业级实践及开源之路》**这本书里找到答案。

在这里插入图片描述

正版购买链接:https://item.jd.com/14328126.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/699586.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

袁庭新ES系列10节 | 使⽤kibana对⽂档操作

前言 在前面的小节中,我们已经给大家介绍了Elasticsearch中文档的相关概念,想必有些同学都已经忘记了,那我们一块儿再来回顾下,文档即索引库中某个类型下的数据,会根据规则创建索引,将来用来搜索。可以类比…

HTML+CSS:动态搜索框

效果演示 这段代码实现了一个简单的搜索栏效果。页面背景为从天蓝色到深蓝色的渐变色,搜索栏包括一个圆形背景的搜索图标和一个输入框。当用户点击搜索图标时,输入框会从搜索图标的位置滑出,显示一个输入框和一个清除按钮。用户可以在输入框中…

Unity(第三部)新手绘制地形

1、创建地形 游戏对象3d对象地形 2、功能 1、 红框内按键为创建相邻地形、点击后相近地形会呈现高亮框、点击高亮区域可以快速创建地形 每块地形面积是1km*1km 2、第二个按钮是修改地形 下面的选择是修改类型 选项含义描述Raise or Lower Terrain升高或降低地形单击左键可…

pikachu靶场-File Inclusion

介绍: File Inclusion(文件包含漏洞)概述 文件包含,是一个功能。在各种开发语言中都提供了内置的文件包含函数,其可以使开发人员在一个代码文件中直接包含(引入)另外一个代码文件。 比如 在PHP中,提供了&…

5G网络(接入网+承载网+核心网)

5G网络(接入网承载网核心网) 一、5G网络全网架构图 这张图分为左右两部分,右边为无线侧网络架构,左边为固定侧网络架构。 无线侧:手机或者集团客户通过基站接入到无线接入网,在接入网侧可以通过RTN或者IP…

如何在Linux Ubuntu系统使用Docker快速部署MongoDB并公网访问

文章目录 前言1. 安装Docker2. 使用Docker拉取MongoDB镜像3. 创建并启动MongoDB容器4. 本地连接测试5. 公网远程访问本地MongoDB容器5.1 内网穿透工具安装5.2 创建远程连接公网地址5.3 使用固定TCP地址远程访问 前言 本文主要介绍如何在Linux Ubuntu系统使用Docker快速部署Mon…

互联网加竞赛 机器视觉 opencv 深度学习 驾驶人脸疲劳检测系统 -python

文章目录 0 前言1 课题背景2 Dlib人脸识别2.1 简介2.2 Dlib优点2.3 相关代码2.4 人脸数据库2.5 人脸录入加识别效果 3 疲劳检测算法3.1 眼睛检测算法3.2 打哈欠检测算法3.3 点头检测算法 4 PyQt54.1 简介4.2相关界面代码 5 最后 0 前言 🔥 优质竞赛项目系列&#x…

8.qt5使用opencv的库函数打开图片

1.配置opencv动态库的环境变量 2.在创建的qt工程中加入如下opencv代码,具体代码如下: 使用opencv库函数显示图片

Linux进一步研究权限-----------ACL使用

一、使用情况 1.1、场景: 某个大公司,在一个部门,有一个经理和手下有两个员工,在操控一个Linux项目,项目又分为三期做,然而一期比较重要,经理带着员工做完了,公司就觉得技术难点已经做完攻克了&#xff0…

【自然语言处理-二-attention注意力 是什么】

自然语言处理二-attention 注意力机制 自然语言处理二-attention 注意力记忆能力回顾下RNN(也包括LSTM GRU)解决memory问题改进后基于attention注意力的modelmatch操作softmax操作softmax值与hidder layer的值做weight sum 计算和将计算出来的和作为memo…

《Python 语音转换简易速速上手小册》第1章 Python语音处理概述(2024 最新版)

文章目录 1.1 语音处理的基础1.1.1 基础知识1.1.2 主要案例:自动语音识别系统案例介绍案例 Demo案例分析1.1.3 扩展案例 1:智能虚拟助手案例介绍案例 Demo案例分析1.1.4 扩展案例 2:情感分析系统案例介绍案例 Demo

NATS学习笔记(一)

NATS是什么? NATS是一个开源的、轻量级、高性能的消息传递系统,它基于发布/订阅模式,由Apcera公司开发和维护。 NATS的功能 发布/订阅:NATS的核心是一个发布/订阅消息传递系统,允许消息生产者发布消息到特定的主题…

2024生物发酵魅力展示会-光德流体

参展企业介绍 河北光德流体控制有限公司始建于1996年,是一家从事以不锈钢为母材的洁净应用材料研发与专业制造的实体企业。产品主要包括卫生级球阀,隔膜阀,蝶阀等,并广泛应用于生物发酵,医疗制药,食品饮料…

初识51单片机

##江科大51单片机学习 什么是单片机??? 单片机,英文名,Micro Controller Unit,简称MCU(tips:有人会简称它为CPU,但不是如此,CPU其实被集成在MCU中&#xff…

视频评论抓取软件|抖音数据抓取工具

最近我们推出了一款基于C#语言开发的工具。这款工具提供了丰富的功能,旨在帮助用户轻松获取抖音视频内容。让我们一起来详细介绍一下这款工具的主要功能模块: 1. 批量视频提取: 工具提供了便捷的批量视频提取功能,用户只需输入关…

第3部分 原理篇2去中心化数字身份标识符(DID)(3)

3.2.2.4. DID文档 (DID Document) 本聪老师:DID标识符和DID URL还都只是ID,必须为它附加一个基本属性才可以证明是该主体独有的。这个就是我们下面介绍的DID文档。 本聪老师:每个DID标识符都唯一对应一个DID文档,也可以说&#x…

潇洒郎:2024 IDEA、Pycharm获取最新激活码获取方式

IDEA获取最新激活码 https://idea.javatiku.cn/ 手机打开,看到验证码,30分钟有效,输入验证码 获取到最新激活码

Redis(十六)缓存预热+缓存雪崩+缓存击穿+缓存穿透

文章目录 面试题缓存预热缓存雪崩解决方案 缓存穿透解决方案 缓存击穿解决方案案例:高并发聚划算业务 总结表格 面试题 缓存预热、雪崩、穿透、击穿分别是什么?你遇到过那几个情况?缓存预热你是怎么做的?如何避免或者减少缓存雪崩?穿透和击穿有什么区别?他两是…

基于大数据的智能家居销量数据分析

文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式 🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 &…

[HTML]Web前端开发技术28(HTML5、CSS3、JavaScript )JavaScript基础——喵喵画网页

希望你开心,希望你健康,希望你幸福,希望你点赞! 最后的最后,关注喵,关注喵,关注喵,佬佬会看到更多有趣的博客哦!!! 喵喵喵,你对我真的…