Page 67 - 《软件学报》2025年第7期
P. 67

2988                                                       软件学报  2025  年第  36  卷第  7  期


                 使得它们难以被直接观测识别出来. 因此, 在针对 C/C++ 语言实现的系统进行测试时, 通常会借助 Address-
                 Sanitizer (ASan) [81] 工具来辅助识别这类内存安全问题. ASan   在编译阶段向程序源代码中插入额外的检查代码, 用
                 于监控内存访问操作. 具体来说, ASan         通过维护影子内存       (shadow memory), 记录每个内存字节的状态, 追踪程序
                 对内存的使用情况. 当程序运行时, 这些插入的检查代码会检测潜在的内存错误, 如堆栈溢出、使用后释放、双重
                 释放等. 如果检测到非法访问或未初始化的内存使用, ASan                会立即报告错误, 提供详细的错误信息和调用栈, 帮助
                 开发者快速定位和修复问题. 这种方法在保持较低运行时开销的同时, 能有效检测出各种复杂的内存错误.

                 3.3.2    差分检测技术
                    相较于崩溃问题, 系统逻辑缺陷更难检测, 因为它们通常不会导致系统的显式崩溃或异常. 在分布式系统中,
                 差分测试是检测逻辑缺陷的常用方法之一. 差分测试的核心思想是使用相同的测试输入传递给不同的分布式系统
                 实现, 然后对比其输出结果. 如果结果出现不一致, 通常表明存在潜在缺陷. 差分测试的优势在于无需了解系统的
                 内部实现细节, 通过对比多个系统实现的输出行为即可发现问题. 图                     9  展示了差分测试的基本流程, 该方法通过对
                 比不同实现的输出, 有效检测出代码逻辑缺陷.

                                                           分布式
                                                                         结果 A
                                                           系统 A
                                          测试输入                              对比
                                                           分布式           结果 B
                                                           系统 B
                                               图 9 分布式系统差分测试示意图

                    典型测试工具      DiffStream [100] 采用差分测试来检测分布式数据流处理系统的逻辑问题. 其主要关注点是检查两
                 个实现对给定输入流是否产生等价的输出流, 即允许逻辑上独立的数据项顺序不同. 由于分布式系统的数据处理
                 通常是并行的, 在差分测试过程中, 两个实现可能会以不同的速率、异步且乱序地产生事件. 为了解决事件输出的
                 乱序性并进行精准的等价输出判断, DiffStream          提出了一种最优在线匹配算法, 用于高效、快速地逐步比较两个
                 输出流的等价性.
                    针对区块链系统的动态测试工具            Fluffy [69] 使用差分对比的测试准则来判断不同以太坊客户端的输出结果. 具
                 体而言, Fluffy  首先基于以太坊客户端虚拟机的执行状态, 通过动态变异生成大量测试交易序列. 然后, 将这些序
                 列作为测试输入, 分别输入到不同版本的以太坊实现中, 包括                    Go  语言版本的   Go-Ethereum  和  Rust 语言版本的
                 OpenEthereum. 通过比较这两种客户端对同一交易序列的执行结果, Fluffy             能够识别出结果不一致的情况, 从而指
                 出至少一个客户端实现中可能存在的代码缺陷.
                    考虑到许多分布式系统只有一种代码实现, 无法直接构造差分对比对象, 典型工具                          Mocket [74] 设计了基于系统
                 设计与实现的差分对比准则. 在设计阶段, 分布式系统通常使用形式化语言                       (如  TLA+ [101] ) 对关键逻辑行为进行建
                 模, 并在形式化验证通过后开始代码开发. 然而, 分布式系统的逻辑复杂性常常导致代码开发过程中引入缺陷, 造
                 成实现逻辑与设计逻辑的不一致. 为了解决这一问题, Mocket 建立了设计模型与代码实现中关键行为状态的映射
                 关系, 并使用状态转移边覆盖引导的模糊测试技术, 生成大量测试用例, 尽可能触发并识别代码实现与模型设计的
                 不一致性, 从而检测出代码逻辑缺陷. 然而, 由于设计模型中的逻辑通常只是代码实现功能的一个子集, 许多非模
                 型中的逻辑缺陷可能会被遗漏.
                    尽管差分测试是一种有效的测试方法, 但它也有一些缺点和限制. 首先, 差分测试只能测试具有相同功能目标
                 的分布式系统逻辑. 由于各个分布式系统通常具有自己设计上的侧重点, 例如同为分布式文件系统, CephFS                               通过
                 提供数据复制和条带化来保障数据的高可用性和耐用性, 适合需要高吞吐量和低延迟的应用; GlusterFS                            侧重于灵
                 活性和简易性, 通过其强大的卷管理功能, 能够轻松扩展存储容量和性能, 适合云存储、媒体流和内容分发网络;
                 而  HDFS  侧重于支持大规模数据处理工作负载, 适合大数据分析、机器学习和数据湖场景. 尽管这些系统的主要
                 功能目标都是分布式文件存储, 但由于侧重点截然不同, 差分测试仅能覆盖它们功能相同的部分, 而无法检测到各
                 自特有的功能逻辑, 从而遗漏大量的潜在缺陷. 此外, 如果用于对比的多个系统实现都存在相同的代码缺陷, 差分
   62   63   64   65   66   67   68   69   70   71   72