写在最前面
本文为邹德清教授的《网络安全专题》课堂笔记系列的文章,本次专题主题为大模型。
冯思乐同学分享了The Scope of ChatGPT in Software Engineering: A Thorough Investigation《ChatGPT在软件工程中的作用范围:一个彻底的调查》
分享时的PPT简洁大方,重点突出
对流程图介绍清晰,没看论文也能理解
论文:https://arxiv.org/pdf/2305.12138.pdf
论文名片
- ChatGPT展示了软件工程(SE)革命的潜力,但高可靠性和风险控制需求引起了对它
缺乏可解释性
的关注。 - 为了解决这个问题,研究者评估了ChatGPT在SE的代码分析中的能力,并将其分解为
语法理解、静态行为理解和动态行为理解
三类。 - 研究重点是ChatGPT
理解代码语法和语义结构
的能力,包括抽象语法树(AST)、控制流图(CFG)和调用图(CG)。 - ChatGPT在跨多种语言的任务中,展示出天赋性的理解代码语法的能力。
- 然而,在理解代码语义,特别是动态语义方面,ChatGPT面临很大的困难。
- 研究得出结论,ChatGPT比较类似于抽象语法树(AST)解析器,展示了
静态代码分析的初始能力
。 - 研究强调了ChatGPT在
解释代码语义结构和编造不存在的事实时容易出现幻觉
。 - 结果表明,需要探索
验证ChatGPT输出正确性的方法
,以确保其在SE中的可靠性。 - (原文没有找到答案,交流后感觉是原文没有提到?欢迎评论交流)研究为为什么LLM生成的代码通常语法正确但易受攻击提供了一个初步的答案。
未来论文的思考
- 将AI模型处理任务的能力
分解为不同的层次
。例如,这些层次可以包括句法分析、语义分析、实体识别、关系提取等。
然后,对于不同的任务,可以根据需求选择合适的层次进行模型的构建和训练。
同时,在评估模型性能时,也可以对模型在不同层次上的表现进行分析和比较,以了解模型的优势和局限性。 - 可以关注的问题包括:模型的可解释性、模型对于不同语言和文本类型的适应性、以及模型在处理异常情况时的稳定性等。同时,也可以考虑如何结合人类专家的经验和知识,提高模型的全面性和准确性。
课堂讨论
chatgpt对语义的理解有局限
构成提示
生成结果不稳定,具备随机性
但论文中正确性的衡量只有一次结果
提示是人工构建的,规范提示效果会不一样
大语言模型
代码理解语义的能力较弱,如果去改进比较麻烦
思考方向:怎么将大模型和具体框架进行结合
背景介绍
ChatGPT 是OpenAI于2022年11月发布的会话人工智能系统。
尽管ChatGPT在软件工程中得到了广泛的应用和讨论,但对ChatGPT在代码语义理解方面的能力
进行深入系统的分析是至关重要的,值得深入研究。
模型是否理解程序语义
动机
实例:保持原始程序语义,同时进行简单的更改,可能导致ChatGPT产生不正确的结果。
对大模型有效性的理解是迫切而重要的。确保软件开发人员能够正确合理地使用ChatGPT来完成任务。
Bucketsort算法需要将数组(即此函数中的“arr”)拆分为多个“counts”,然后对每个“counts”单独排序。
因此,我们可以发现修复这个错误函数的正确版本是,
将第二个循环中的变量“arr”替换为变量“counts”
。图2与前面的例子一样,但ChatGPT无法修复这个有bug的函数。
研究设计
从理解程序语法、静态行为和动态行为的角度,对ChatGPT理解程序语义的能力进行了逐步分析。
程序语法:抽象语法树(AST)生成和表达式匹配(expression matching)
静态行为:控制流图(CFG)生成、调用图(CG)生成、数据依赖分析( data dependency analysis)、污点分析( taint analysis )和指针分析( pointer analysis )
动态行为:等效突变检测( equivalent mutant detection )和不可靠测试推理( flaky test reasoning)
RQ
RQ1: ChatGPT能很好地理解代码语法吗?
RQ2: ChatGPT能理解代码静态行为吗?
RQ3: ChatGPT能理解代码的动态行为吗?
程序语法
抽象语法树生成:AST是代码分析的核心结构,代表了程序设计语言的语法。对于处理某些SE任务至关重要,例如生成语法正确的代码。
表达式匹配:表达式简洁,便于分析,并且所有表达式令牌都具有语法角色。在不理解这些语法角色的情况下进行逐字匹配会导致较差的性能。
从输入代码中找到与目标数学表达式相似的表达式。
静态行为
控制流图生成
控制流图(CFG)分析通常是程序分析的第一步,因为它估计语句执行的顺序。理解CFG对于代码模型识别语句之间的关系至关重要。CFG是静态分析中的核心代码结构,广泛应用于软件工程中,解决漏洞检测、代码优化、程序分析等各种任务
调用图生成
调用图是描述程序中函数之间调用关系的图表。
要用神经网络对代码建模,理解一个复杂的程序是必不可少的。因为它提供了对代码中的函数关系的洞察。
这三个任务反映了对代码分析至关重要的数据流信息。
数据依赖分析是一种强大的代码分析和优化技术,可以揭示程序中不同变量之间的数据关系。说明数据是如何在程序中传播的,对于代码模型解决SE任务(如漏洞检测)非常有用。
污点分析可以用来检测变量是否可以被外部源污染。这项任务考验了人工智能模型的基于数据依赖分析的推理能力。
指针分析是软件工程中一个具有挑战性的问题,它分析的是指针所指向的存储位置。
等效突变指的是改变后的程序具有与原始代码相同的行为。它直接关系到代码的动态行为。
不可靠的测试指在多次运行时,一个测试的输出不一致。不稳定的测试通常是由一些不确定的函数、环境状态和执行计划引起的。
不可靠的测试推理需要ChatGPT解释为什么在相同的设置下,测试有时通过,有时失败。
提示设计
角色提示
将特定的角色分配给ChatGPT,为模型提供任务上下文,以有效地生成所需的输出。
6个角色: AST解析器,表达式匹配器,控制流图分析器,调用图分析器,代码静态分析器,和指针分析器。
[LANG]
指的是用于分析代码的编程语言。
[TASK DESCRIPTION]
概述了ChatGPT要执行的预期任务。
[OUTPUT FORMAT]
提供输出规格。
[INPUT]
作为被分析代码的占位符。
指令提示
指令提示符不为ChatGPT分配特定的角色,相反,它们提供命令。这些提示对于涉及多个角色或没有任何适用角色的任务通常很有用。
[DOMAIN KNOWLEDGE]
解释与任务相关的领域知识。
[EXAMPLE CODE]
为任务演示提供与领域知识相关的示例代码。
实验结果
数据集
准则:由于ChatGPT是基于2021年底的互联网数据进行训练的,因此为了避免数据泄露的风险,使用程序工具生成的新数据或最近创建的数据集。
语法分析——AST生成
在总共32个样本中,大多数生成的ast是合理的,其中合理的有26个,不合理的有6个(用绿色条表示)。在26个合理的ast中,12个没有问题(用蓝色条表示),而其余的ast有轻微问题(用橙色条表示)。
缺少语句令牌(Sta tokens): Sta Tokens类别表示语句中的一些令牌缺失,例如 在”System.out.print(a);中缺少”System” 令牌。
缺少语法令牌(Syn token): Syn令牌类别表明缺少一些与语法相关的令牌,例如”public” and ”private”访问修饰符。
错误的结构:错误结构(Wrong Structure)表示AST结构错误,如if-else结构错误。错误结构类别是严重的,它意味着AST包含错误的语法结构。
语法分析——表达式匹配
ChatGPT认为如果两个表达式使用相似的运算符,具有相似的顺序,并且具有相似的变量数量,则两个表达式是相似的。
虽然ChatGPT可以识别匹配表达式所在的行号或包含匹配表达式的函数的起始行号,但对于这32个匹配样本的表达式,在这两种情况下,行号都不准确。
ChatGPT对于代码的语法结构和代码令牌的语法角色有一定的理解
冗余:冗余类别包括无意义的节点,如null节点
编造:包含不存在的节点或语句
错误结构:错误结构类别是指结构不正确的cfg,例如表示不正确的循环语句
冗余问题是次要的,因为它们不影响控制流程,而制造和错误的结构问题是严重的,因为它们改变了控制流程。
在8个错误的结构问题中,5个在表示循环控制流方面存在问题,2个在表示ifelse控制流方面存在问题。
在检查AST和CFG生成任务中确定的问题后,一些严重的问题通常会出现在循环和if-else语句中,这说明ChatGPT似乎对循环和if-else语句的语法和静态行为的理解较弱。
静态分析——数据依赖和污点分析
性能不如静态分析工具Slither
污点分析的效果甚至不如数据依赖分析
F1分数在不同的项目中是不同的,差异很大,大约在0.2到1.0之间。这表明ChatGPT在不同的数据分布(即项目)上的表现有很大的差异。
静态分析——指针分析
由于一个指针可以指向多个变量,计算每个指针的预测集和基本真值集之间的Jaccard Index
ChatGPT对43个指针做出了正确预测,45个指针做出了完全错误的预测。对于44个指针只提供了一半的正确预测。
计算了每个程序的平均Jaccard索引,以评估ChatGPT是否在不同的项目中是不同的。我们观察到该指数的范围为0到1,中位数约为0.6。这些发现表明,ChatGPT确实受到项目数据不同的影响。
ChatGPT具有代码静态分析的基本功能。
然而,ChatGPT存在编造问题,导致不存在的元素的出现。
此外,ChatGPT的性能根据给定的任务可能会有所不同。
动态分析——数据依赖和污点分析
在提示中使用示例代码可以提高召回率(从0.40提高到0.46),但降低精度(从0.85降低到0.70)。
等效的突变示例,指导ChatGPT将与示例相似的突变标记为正突变。由于使用多个不同的示例,ChatGPT倾向于分配更积极的标签
从两种提示的混淆矩阵。我们可以看到,ChatGPT有样例代码预测了66个阳性样本,而没有样例代码预测的阳性样本减少到47个。
排除提示中的示例代码得到准确率0.17的结果。
在提示符中包含示例代码得到精度为0.11的结果。
绿色条表示ChatGPT不确定的预测数,橙色条表示不正确的预测数,蓝色条表示正确的预测数。
蓝色条,发现有示例代码的提示学习效果不如没有示例代码的提示学习效果
绿色条,发现有示例代码的ChatGPT比没有示例代码的ChatGPT对其响应更有信心。
无论有没有示例代码,预测效果都不好
讨论
限制
数据集量过小:研究没有使用大型数据集进行分析,因为大型数据集分析的成本高昂(依赖人工的判断)。
人工提示:研究采用人工设计提示,优秀的提示可能会有更好的结果。
只依靠结果进行分析:由于ChatGPT的权值难以获取,无法使用通常用于分析预训练模型的权值分析,只能进行黑盒分析。
程序小规模:作为transformer架构,ChatGPT施加了最大令牌限制,限制了研究中的输入上下文,在评估中不使用非常大的程序。
这篇文章的结论过于简单,只给出了表面上的观察,没有更加深入的思考
在不同的项目中的实验结果有好有坏,但是没有更深入的探究造成这一现象的原因是什么,什么类型的项目能够得到更好的结果
这些调查能够为软件工程领域的发展作出什么贡献
测试失败的原因总结
并发引起的
系统涉及到多线程,线程执行顺序是不确定的,而开发人员写的测试用例只应对了部分线程执行顺序,当某些测试运行中出现了未考虑到的执行顺序时,就会导致测试运行失败。
异步引起的
系统涉及到异步通讯,其通讯时间是不确定的。开发人员在写测试用例的时通常会预估一个相应的时间,大部分情况下,异步通讯都能够在预估时间内执行完成,测试用例成功运行,然而也有异常情况,即异步通讯时间超过预估时间,导致测试失败。
执行顺序依赖引起的
有些测试用例会依赖特定的测试用例执行顺序,如果执行顺序改变了,测试就会失败,比如Test1是检测一个链表是否为空,Test2是检测能否向该链表中插入一个元素。如果执行顺序是Test1 -> Test2,那么测试就能成功。如果是Test2 -> Test1,测试就会失败。
资源泄露引起的
有些测试用例会导致资源泄露,比如内存泄露。如果测试机器的负载较轻,测试能够成功完成,如果负载较重,则可能因资源不够而导致测试失败。
系统时间引起的
很多测试用例涉及到系统时间,程序员经常以某个特定时区的时间为准,而测试用例可能会在别的时区内执行,就会导致有些时段测试成功,有些时段测试失败。
返回值区间要求过于严格引起的
开发人员通常会使用预定好的值来判断测试是否成功,有时设定的值的范围过于严格,会导致某些执行结果落在预定值之外,导致测试失败。
随机数引起的
开发人员有时候会在测试用例中使用随机数,当某些边界值没有考虑到时,就会导致测试用例执行失败,比如除数是随机数时,就可能出现除以0的情况。