代码级质量技术之基本框架介绍

news2024/11/17 4:39:39

在这里插入图片描述

作者 | CQT&星云团队

一、背景

代码级质量技术:顾名思义为了服务质量更好,涉及到代码层面的相关技术,特别要指出的是,代码级质量技术不单纯指代码召回技术,如静态代码扫描、单元测试等。

研究代码级质量技术主要有以下几个方面的原因:

1、随着精准测试等概念的兴起,对代码覆盖率的依赖逐渐加重,代码插桩的性能、准确性、时效性等都成为业界要解决的难题;

2、随着智能化,尤其是基于风险驱动的测试发展,对代码的理解需要得到突破,才能更好的从代码实现中挖掘风险、判断风险;

3、在黑盒级别的测试,质量工作者往往是通过对象的返回或外在表象观测对下的异常表现进而发现问题,但是其实可能很多潜在的异常并没有到“肉眼”可观测到的级别而导致问题漏出,这时候就需要有更多的对象更细的运行数据来供质量工作者分析去发现问题的蛛丝马迹,诸如:内存泄露、性能恶化等,所以业界有很多prof、火焰图、asan等偏白盒动态检测问题的技术出现;

4、代码作为产生实际问题最前沿的阵地,大部分问题都可以归因到某段代码不合理,如果可以在代码级别直接召回问题,无论从仿真复杂度、修复成本、定位成本等均会得到极大改善;

5、代码是工程师交流的舞台,通过对代码级质量技术的研究和规范,可以促进代码更加的具备鲁棒性和更优质的设计如单测提升可测性等,也可以促进质量保障人员对代码加深掌控与理解,进而在质量保障各类场合发挥关键作用。

从指导质量行为、极大提升召回问题能力、增强代码鲁棒性、提升人员对代码的掌控力等多个方面,都可以看出代码级质量技术的关键且不可替代作用,百度质量效能平台于2019年开始关注和投入该方向,在代码理解、代码探针、代码质量技术应用等多个层级多方面进行探索和落地,接下来的文章中会依次为大家介绍。

二、代码级质量技术架构

要理解代码级质量技术的原理和后续的主要应用场景,首先要理解代码从语言到可执行态的基本过程,下面以C++为例说下基本过程:

C++从代码到可执行bin文件,主要分为四个阶段:预处理、编译、汇编和链接。

预处理:处理一些#号定义的命令或语句(如#define、#include、#ifdef等),生成.i文件;

编译:进行词法分析、语法分析和语义分析等,生成.s的汇编文件,大家熟悉的AST抽象语法树就在该过程产生;

汇编:将对应的汇编指令翻译成机器指令,生成二进制.o目标文件;

链接:链接分为两种,静态链接:将静态链接库中的内容直接装填到可执行程序中;动态链接:只在可执行程序中记录与动态链接库中共享对象的映射信息。

代码级质量技术的技术原理,主要是获取到该过程的代码片段数据或植入对应的目标代码,来达到对应的质量目标,如获取片段数据可以用来理解代码判断风险,可以用来指结构化代码结构,供自动生成单元测试和代码检测提供基础数据;如植入对应目标代码,可以用来做插桩(即覆盖率采集)或动态数据采集等。

基于上述介绍与理解,我们把代码级质量技术划分大范围为两个层次,两个层次内包含多个层次,如下图所示:

图片

大层次一:代码理解,CodeC(Code Comprehend):偏底层技术,基于底层AST等能力、分析出代码的特性(AST、调用链、依赖等)和风险度,通过API、SDK等方式对外提供基础服务

  • 存储层:主要用来代码编译过程的基础数据和对应的数据存储选型调优等,在这个过程主要难点在于基础工具的选型和过程性能的调优,以达到可以在业务应用的目标;

  • 分析层:分析层是依托基础的数据,根据特定的要求,对数据进行结构化的建模,如函数调用链、依赖关系等,做好基础的分析供上层应用;

  • 模型层:用于通过分析层和基础数据,去训练代码存在的潜在风险或风险偏向(性能问题突出等);

  • API层:通过API、SDK等方式对外提供基础服务。

该层会遇到众多技术挑战,如要适配不同语言的解析器、编译过程;基础框架进行代码调优;分析过程数据缺失修复等,是一项非常细致且有技术挑战的工作,当然我们在该过程也会探索出一些技术经验供大家参考。

大层次二:代码级质量技术应用,Codeπ:主要是依托代码理解的过程或产出,植入对应的信息,以达到对应的质量目标,这个层次应用场景是关键,因此我们是以解决问题的目标为导向,对该层次进行细分,所以目标或应用场景的不同会使得该层次的分类会不断增加,目前分为以下四类:

  • CodeQ(Code Quality): 与召回问题相关(智能UT、基于规则的代码缺陷检测、基于AI的代码缺陷检测、火焰图、ASAN等在个分类);

  • CodeP(Code Probe):与动态插桩相关(ccover、covtool、jacoco、gocov等在这层),主要是往代码里面植入探针获取运行行为数据;

  • CodeH(Code Health):评估代码健康度(类似sonarcube等)、代码风险度评估用于决策后续的质量行为;

  • CodeDL(Code defect location):代码缺陷定位。

下面的章节我们会分布从第二级的层次,为大家做基本原理和过程介绍,后续还会有系列发文再深入的介绍对应实现内容。

三、代码理解层介绍

代码理解是一个以软件程序为对象,对其内部的运作流程进行分析,获取相关的知识信息,这些信息可以用于软件开发、软件测试、软件维护等各个阶段,旨在对程序进行性能优化和正确性验证。代码理解常用的分析方向有静态分析、动态分析、非源码分析3类,但是随着LLM大模型的发展,我们也正在研究模型在代码理解领域的突破与应用。

图片

静态分析:是指在不运行代码的方式下,通过词法分析、语法分析、控制流、数据流分析等技术对程序代码进行扫描,验证代码是否满足规范性、安全性、可靠性、可维护性等指标的一种代码分析技术。

动态分析:软件系统在模拟的或真实的环境中执行之前、之中和之后,对软件系统行为的分析。

非代码分析:主要是对数据文件、配置文件等非源码文件和源码间进行关联分析,当代码仓变更时,能感知变更内容对源码、功能的影响。

动态分析多为对程序进行的一些功能测试或性能测试等对程序的运行结果,资源使用情况的相关程序分析工作。故本小节主要介绍静态程序分析相关的代码理解技术,不对动态程序分析做展开。

静态程序分析在不执行程序程序的情况下对程序进行分析,分析的对象可以是针对特定版本的源代码或者二进制文件,通过词法分析、语法分析、控制流、数据流分析等技术对程序代码进行扫描,根据不同的分析目标,得到对应的分析结果。在学术界和工业界主要应用在软件安全领域,验证代码是否满足规范性、安全性、可靠性、可维护性;在百度内部,除漏洞检测外,静态程序分析还包括多维度的代码分析和度量手段,在交付系统和监测系统中被广泛使用。

业界静态分析一般基于以下4种方式展开:

  • 关键字匹配,基于正则表达式分析

  • 基于AST的代码分析,结合正则表达式和关键字能力

  • 优点:结合语法和语义,可以引入作用域等更多概念,更准确。

  • 缺点:无法应对所有场景,另外,基于AST来分析得到的数据流,忽略了分支、跳转、循环等影响执行过程顺序的条件,缺少控制流信息。

  • 基于IR/CFG的代码分析等自制的中间语言数据结构分析

  • 属于当前比较主流的代码分析方案,例如被源伞,实现了多种语言生成统一的IR,这样一来对于新语言的扫描支持难度就变得大大减少。

  • IR:是一种类似于汇编语言的线性代码,其中各个指令按照顺序执行。其中现在主流的IR是三地址码(四元组),例如llvm的IR。

  • CFG:(Control flow graph)控制流图,在程序中最简单的控制流单位是一个基本块,在CFG中,每一个节点代表一个基本块,每一个边代表一个可控的控制转移,整个CFG代表了整个代码的的控制流程图。基于IR来生成得到CFG。

  • 基于QL(Query Language)分析

  • 例如codeQL,把源代码转化成一个可查询的数据库,通过 对源代码工程进行关键信息分析提取,构成一个关系型数据库。安全漏洞、Bug 和其他错误被建模为可针对从代码中提取的数据库执行的查询。

常用的静态程序分析技术:

  • 数据流分析

  • 数据流分析收集程序运行到不同位置时各个值的信息和它们随时间变化的信息。污点检验是一个典型的通过数据流分析进行程序风险检测的例子,它会找到所有的可能被使用者修改的变量(也就是有“污点”、不安全的变量),并阻止这些变量在被修复安全漏洞前被使用。

  • 控制流分析

  • 用于分析程序控制流结构的静态分析技术,目的在于生成程序的控制流图,在污点分析、编译器设计、程序分析、程序理解等领域都有重要应用。

  • 指针分析

  • 指针分析主要用于分析指针所有可能指向的对象,它会分析出一个指针所指向的内存位置和所对应的对象。可以用于调用分析、代码优化、Bug追查、安全性分析与验证测试。

四、代码级应用之探针

代码探针,也是插桩技术,它是在保证被测程序原有逻辑完整性的基础上在程序中插入一些探针(又称为“探测仪”,本质上就是进行信息采集的代码段,可以是赋值语句或采集覆盖信息的函数调用),通过探针的执行并抛出程序运行的特征数据,通过对这些数据的分析,可以获得程序的控制流和数据流信息,进而得到逻辑覆盖等动态信息,从而实现测试目的的方法。

不同语言的插桩技术有所不同,常见的技术有:ccover、covtool、jacoco、gocov。

CodeP代码探针可以应用在: 代码监控(方法执行耗时等),代码分析(函数、数据流的跟踪等),业务埋点。

除此之外,代码探针最常见的场景是代码覆盖率采集。

图片

4.1 覆盖率

代码覆盖率,是软件测试中的一种度量,描述程序中源代码被测试的比例和程度,所得比例称为代码覆盖率 ,分析未覆盖部分的代码,从而反推在前期测试设计是否充分,没有覆盖到的代码是否是测试设计的盲点。覆盖率统计的分类包含:

行覆盖率:行覆盖率是最基本的指标,表示是否代码中的每个可执行语句都被执行过;

分支覆盖率:分支覆盖使用一组测试参数来测试是否代码中所有的分支都能被测试到了;

路径覆盖率: 对包括所有分支在内的所有的路径都能测试一遍,这就是路径覆盖;

变更行覆盖率:上一次发布代码后更新的代码的行覆盖率,这个数据可以方便的看出新的代码是否做了测试。

覆盖率的业务使用场景广泛比如:RD自测、RD准入、QA准出、外包评估、精准测试、集成测试、基线升级评估、灰度测试评估,自动化测试能力评估、众测等。

代码探针实现覆盖率统计的步骤如下:

1、识别待插桩的函数

2、用codep技术对函数进行插桩,插桩技术分为:

  • 源码插桩: 侵入式的在源代码的基础上替换或者插入另外一些代码

  • 编译过程插桩: 在字节码文件中写入桩函数 (如asm、javassit等技术)

3、探针采集覆盖信息整合, 统计覆盖率数据

五、代码级应用之召回

从召回异常问题的角度介绍两类代码级技术应用:智能UT、SA。与现有异常测试方法进行对比分析,压力测试、功能测试依赖编译运行且需人工构造异常场景,存在高成本、低召回的问题。而智能UT和SA基于白盒分析产出的数据可以提前、快速、低成本、轻量级地召回异常问题。

5.1 智能UT

单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证,这里的最小测试单元是指函数或者类。在问题召回层面,UT针对最小单元进行测试,构造数据简单、易于验证正确性,便于后续功能的回归,能够更早地发现问题,定位和解决问题成本低。

传统UT依赖开发人员人工编写单测代码来进行测试,存在开发成本高、依赖人的意识等缺点。基于单测的基本原理衍生出了智能UT工具。智能UT通过自动的分析函数和随机的构造测试数据,可自动生成异常单元测试代码,生成的代码可以直接用于单元测试任务,单元测试运行后,智能UT工具能分析代码中存在的稳定性问题。

如下图展示,智能UT建设的主要思路是将一个开发人员编写单元测试代码的过程进行拆解,将整个过程抽象为确认待测试函数->分析代码->构造测试数据->生成测试代码四个步骤,利用白盒数据和一系列算法模拟上述单测代码生成的过程从而自动地生成异常单元测试代码并应用于单元测试任务。

图片

△UT与智能UT过程对比

5.2 SA-基于规则的代码缺陷检测

SA(static analysis)意为静态代码扫描,整个扫描过程无需编译运行,仅通过词法分析,语法分析,语义分析等技术对代码进行扫描,进而发现代码逻辑错误和编程缺陷。依据编程语言的自身特性,可将各类风险场景提取转化为通用的规则进行异常拦截。现有SA检查是通过依赖代码分析、基于通用的风险规则进行代码缺陷检查的静态代码扫描工具,可召回例如空指针访问、数组越界、除零等风险问题。

下图展示了基于规则的静态代码检查处理流程。

图片

△SA处理流程框架

优点:无需编译运行、资源消耗少,扫描分析过程高度自动化、不依赖人力。

缺点:依赖后验知识、存在滞后性,依赖人开发规则、准召低、可持续性差。

此外在代码级领域还有专门被测对象动态行为的检测技术,用于发现程序细微的异常,比如业界常用的火焰图、gprof、ASAN等工具,就是在程序运行时收集程序表现数据,用于检测程序异常问题。

六、代码级应用之孤岛函数识别

6.1 什么是孤岛函数

不被调用的函数被称为孤岛函数。如果一个函数已不再被调用,就成了无用的废弃函数。

6.2 为什么要做孤单函数识别

无用函数属于技术债治理的场景之一,无用代码的存在增加了软件开发、测试、以及问题排查的开销,例如QA和RD需要更多额外的精力来评估需求的影响范围。

通过孤岛函数识别的能力可以做无用代码和相关用例、配置、数据的清理,提升代码可维护性,同时提升问题的排查效率。

6.3 如何识别孤岛函数

1、静态分析方法

原理:通过函数调用分析,获取入度为0的函数,再结合不同语言特性,筛选出实际未被调用的函数。例如:c++语言中构造函数等非显式调用的函数、纯虚拟函数等函数特性。

  • 优点:执行速度快,开发成本低。

  • 缺点:受限于不同语言特性,识别准确率需要持续优化。例如:配置反射调用、多态特性下识别准确率更低。

2、动态分析方法

原理:通过探针的方式,在程序运行时对函数调用栈进行记录,一般是基于抽样或者开关的方式来控制。

  • 优点:识别准确率相比静态分析方法要高。

  • 缺点:代码侵入对性能有损,同时也受限于流量丰富度,可能需要接入适配。

3、动静结合方法

将上述两种方法结合起来时使用,进行能力互补。

这篇文章更多的是从背景、结构和各个层的基本概念介绍了代码级质量技术的概况,接下来的文章将会在各个方面、各个层级进行展开,欢迎大家关注和一起探讨。

---------- END ----------

推荐阅读【技术加油站】系列:

基于openfaas托管脚本的实践

百度工程师移动开发避坑指南——Swift语言篇

百度工程师移动开发避坑指南——内存泄漏篇

百度工程师教你玩转设计模式(装饰器模式)

揭秘百度智能测试在测试定位领域实践

百度工程师教你玩转设计模式(适配器模式)

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

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

相关文章

1.6 初探JdbcTemplate操作

一、JdbcTemplate案例演示 1、创建数据库与表 (1)创建数据库 执行命令:CREATE DATABASE simonshop DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; 或者利用菜单方式创建数据库 - simonshop 打开数据库simonshop &#x…

边缘计算盒子在视觉分析领域的优势

边缘计算盒子在视觉分析领域有广泛的应用。边缘计算盒子是一种集成了计算、存储和网络连接功能的设备,通常部署在物理环境中的边缘位置,如工厂、城市、交通系统等。它们能够在离数据源更近的位置进行实时数据处理和分析,从而提供更低的延迟和…

使用Docker安装Kafka

第一步:使用下述命令从Docker Hub查找镜像,此处我们要选择的是zookeeper官网的镜像 docker search zookeeper 第二步:拉取zookeeper镜像 docker pull zookeeper:latest 第三步:启动zookeeper容器 docker run -d --name zookee…

微服务-Elasticsearch基础篇【内含思维导图】

Elasticsearch官网:欢迎来到 Elastic — Elasticsearch 和 Kibana 的开发者 | Elastic 注意:Elasticsearch官网访问和加载的耗时很长!!! Lucene官网:Apache Lucene - Welcome to Apache Lucene 目录 一、E…

Docker基本操作与自定义镜像Docker-Compose与Docker镜像仓库

目录 一.基本操作 1.镜像操作 1.1.镜像名称 1.2.镜像命令 1.3.案例-拉取、查看镜像 1.4.案例-保存、导入镜像 2.容器操作 2.1.容器相关命令 2.2.案例-创建并运行一个容器 2.3.案例-进入容器,修改文件 2.4.小结 3.数据卷(容器数据管理&#x…

挑选在线帮助文档协作工具的技巧与要点

随着互联网的发展,越来越多的公司和团队开始使用在线帮助文档协作工具来共同编辑和维护文档。这些工具可以让多个用户同时协作编辑同一篇文档,从而提高工作效率和减少沟通成本。然而,在选择在线帮助文档协作工具时,需要注意一些技…

低代码平台投票榜揭晓:这些平台最受欢迎

低代码平台是软件开发工具,允许用户快速轻松地创建和部署应用程序,只需最少的编程知识。对于寻求在不需要大量IT资源的情况下构建自定义应用程序的企业来说,这些平台非常有用。在本文中,我们将讨论低代码平台排行榜投票榜&#xf…

注解和反射复习

注解 注解:给程序和人看的,被程序读取,jdk5.0引用 内置注解 override:修饰方法,方法声明和重写父类方法, Deprecated:修饰,不推荐使用 suppressWarnings用来抑制编译时的警告,必须添加一个或多个参数s…

外贸客户背调的几种干货技巧

外贸人要想做到知己知彼,那背调是必不可少的。 有经验的外贸人会通过关键词、邮箱等开展模糊搜索,然而这种方式不光效率低,而且搜索到的信息也不全。今天小编分享的这几种背调组合工具,不光收集到的客户信息全面,而且…

Nginx网络服务的配置(叫不醒和睡不着的是两个世界)

文章目录 一、Nginx概述二、Nginx相对于Apache的优点三、配置Nginx网络服务1.编译安装和启用Nginx服务(1)关闭防火墙和selinux(2)安装依赖包(3)创建运行用户、组(Nginx 服务程序默认以 nobody 身…

华为OD机试真题B卷 Java 实现【机房布局】,附详细解题思路

一、题目描述 小明正在规划一个大型数据中心机房,为了使得机柜上的机器都能正常满负荷工作,需要确保在每个机柜边上至少要有一个电箱。 为了简化题目,假设这个机房是一整排,M表示机柜,I表示间隔,请你返回…

北斗RTK差分定位技术原理、优势及应用领域

北斗卫星导航系统是中国自主建设的卫星导航系统,是继美国GPS、俄罗斯GLONASS和欧盟Galileo之后,全球第四个卫星导航系统。北斗系统非常重要,可用于国防、公共安全、民生等多个领域,包括交通运输、环境保护、渔业等。差分定位则是北…

【Springboot系列】springboot扩展点大整理,赶紧收藏起来

系列文章:Spring Boot学习大纲,可以留言自己想了解的技术点 1、aware系列 在Spring Boot中,有一些可以实现的Aware接口,用于在应用程序中获取特定的上下文或对象。这些接口允许您的组件意识到它们所在的环境,并与之进…

和数集团元宇宙场景落地 催生新机遇

现代社会随着科技不断发展,人们对于虚拟现实的需求日益提高。随着互联网进入Web3.0时代,越来越多的人开始进入虚拟世界,探索虚拟现实的无限可能。 在这个充满未知的广阔世界中,和数集团旗下包括【神念无界源起山海】、【神宠岛】…

国内使用chatGPT插件

无需任何繁琐操作,只要你一打开edge浏览器就能使用chatGPT,还要什么自行车! 那么如何使用呢?其实操作是非常简单的! 步骤 第一步:下载edge浏览器 edge浏览器一般Windows10系统都自带了,没有的…

ChatGPT 提示的艺术 —— 如何编写清晰有效提示指南

ChatGPT 提示的作用 正如我们之前提到的那样,ChatGPT 对话中使用的提示的质量可以显著影响对话的成功。定义清晰的提示可以确保对话保持在正确的轨道上,并涵盖用户感兴趣的主题,从而产生更引人入胜和信息丰富的体验。 那么什么样的 ChatGPT…

计算机网络实验:认识Packet Tracer软件

目录 前言实验目的实验内容及要求相关知识点实验指导实验过程总结 前言 计算机网络是当今信息技术的重要组成部分,它涉及到多种硬件和软件的协同工作,以实现数据的传输和交换。为了更好地理解和掌握计算机网络的基本原理和技术,我们需要进行…

关于分数的二进制原反补码的求解

话不多说,上例子 求-53/64的原反补; 前奏:-53/64可以分解为符号位“-”和数字位53/64; 第一步:在计算机中,符号位用0表示“”用1表示“-” 第二步:求53/64的二进制数,过程如下图…

如何回馈 Elastic 社区

作者:Ully Sampaio 在 Elastic 社区中拥有前排座位最美妙的事情之一就是见证人们互相帮助。 从讨论和 Elastic Community Slack 工作区到 Elastic YouTube 官方频道,无论你走到哪里,你都会看到 Elasticsearch 专家和初学者分享他们的知识。 这…

图解LeetCode——543. 二叉树的直径

一、题目 给你一棵二叉树的根节点,返回该树的 直径 。 二叉树的 直径 是指树中任意两个节点之间最长路径的 长度 。这条路径可能经过也可能不经过根节点 root 。 两节点之间路径的 长度 由它们之间边数表示。 二、示例 2.1> 示例 1: 【输入】roo…