Page 125 - 《软件学报》2026年第7期
P. 125

2810                                                       软件学报  2026  年第  37  卷第  7  期


                    (2) TPL  复用检测面临特征粒度选择问题, 粗粒度特征误报较少但易漏报, 细粒度特征漏报较少但误报增多.
                 在库粒度复用检测中, 粗粒度特征 (如文件粒度) 能够减少误报, 但缺乏应对代码结构变化的灵活性, 特别是当目
                 标代码对复用文件进行函数级别的增删或重排时, 结构变化会导致文件相似性降低, 导致漏报                             TPL. 而细粒度特征
                 (如函数粒度) 虽然能应对代码结构变化, 但在库粒度报告时容易产生误报 (见限制                        1). 为了减少误报, 通常需要提
                 高函数复用的数量阈值, 这会导致召回率下降, 因为一些少量复用情况可能被漏检. 因此, 如何平衡细粒度特征和
                 粗粒度报告, 保持较低的误报率的同时提高召回率, 仍是一个亟待解决的问题.
                    (3) TPL  在目标代码中的结构变化增加了依赖分析的难度. TPL               的复用往往伴随修改, 例如, 原本属于同一文
                 件的函数可能被分散到不同文件中, 或一个文件可能包含来自多个                      TPL  的函数, 这使得   TPL  成分划分更加困难.
                 若划分不准确, 可能会导致依赖关系分析的冗余或遗漏. 此外, 若多个同名头文件存在于相同路径层级, 仅依赖
                 “#include”语句进行分析将难以准确判断被包含的文件, 从而引发依赖关系解析错误, 进一步加大分析难度.
                    为解决以上挑战, 本文提出了          CAnalyzer, 一种有效的针对    C/C++源代码的   SCA  技术. CAnalyzer 以  C/C++源
                 代码作为输入, 输出源代码中复用的           TPL  成分和  TPL  之间的依赖关系.
                    (1) 为了减少公共函数对       SCA  检测结果的干扰, CAnalyzer 对融合多托管仓库构建的           TPL  特征库中的函数进
                 行了原始   TPL  归属识别处理. 首先, CAnalyzer 通过函数路径等标识信息, 过滤掉与特定               TPL  无关的噪声函数; 其
                 次, 采用聚类算法将相似        TPL  归为同一“家族”. 每个家族内部的成员共享部分公共函数, 同时也包含各自独有的
                 标志函数. 基于“被复用库中标志函数占比较低”的假设, CAnalyzer 分析各                TPL  之间共享公共函数的复用关系, 从
                 而有效区分    TPL  自身代码与外部代码, 并剔除不属于特定             TPL  的公共函数. 最终构建的      TPL  特征能够更加准确
                 地反映其真实的函数归属情况, 避免了公共函数对后续分析结果造成干扰.
                    (2) 为了应对特征粒度选择问题, CAnalyzer 采用函数粒度特征相似性计算, 同时结合函数、文件和库粒度多
                 级复用阈值准确识别复用的          TPL. 首先, 将  TPL  库拆解为细粒度的函数级特征与目标代码对比, 从而确保即使复
                 用的函数分散在不同的        TPL  文件中, 也能够准确识别其复用情况. 随后, 在函数复用比例达到设定阈值后, 进一步
                 分析文件层面的复用比例; 最后, 综合考虑整库层面的复用比例, 判断目标代码是否复用了该                            TPL. 若函数、文件
                 和库这   3  个层次的复用比例均达阈值, 则可确认该           TPL  为目标代码的有效成分. 通过递进式分析, CAnalyzer 实现
                 了从函数到文件再到整库的多级阈值识别策略, 既能灵活应对代码结构的变化, 又能有效降低误报.
                    (3) 为了应对目标代码中       TPL  结构变化带来的依赖分析问题, CAnalyzer 首先明确划分           TPL  模块, 并通过分析
                 文件级依赖关系推导        TPL  间的依赖. 基于   SCA  结果, 结合目标代码的目录结构和元数据信息, CAnalyzer 采用             4
                 项划分标准, 将目标代码划分为不同的            TPL  模块, 每个模块包含多个文件, 从而将          TPL  间的依赖关系抽象为文件
                 集之间的依赖关系. 通过分析#include 和        extern  语句, 识别模块间的直接依赖关系. 然而, 直接依赖关系可能会遗
                 漏, 例如头文件冲突或       TPL  模块划分不准确时, 可能导致依赖关系无法正确识别. 为弥补这些遗漏, CAnalyzer 通
                 过类、枚举、结构体等标识符推断间接依赖关系.
                    为了评估    CAnalyzer, 我们构建了一个高质量的评估数据集, 分别从              GitHub  和  Gitee/OpenHarmony  收集了
                 200  个  C/C++语言项目的源代码, 涉及     515  个被复用的  C/C++ TPL. 实验结果表明, 在    TPL  检测任务中, CAnalyzer
                                                                                             [14]
                                                                                     [13]
                 的精确率和召回率分别达到了          90.6%  和  86.6%, 显著优于当前主流的   SCA  工具: CENTRIS 、TPLite 和  OSSFP .
                                                                                                      [15]
                 在依赖关系检测方面, 我们以         OpenHarmony  项目中的  1 784  对文件依赖关系作为标准集, CAnalyzer 实现了       94.8%
                 的精确率和    99.0%  的召回率, 充分满足自动化构建         TPL  依赖关系的需求. 此外, 我们还评估了特征库预处理和多
                 级阈值策略对     TPL  检测性能的影响, 实验结果显示, 召回率保持在             86.6%  时, 经过多阶段预处理后的特征库将精
                 确率提升   25.6%–74.0%. 在效率方面, CAnalyzer 在支持大规模特征库的同时, 实现了较高的检测效率 (969.5 s).
                    本文的主要贡献如下.
                    (1) 全面覆盖  C/C++ TPL  的特征库. 创建了一个    C/C++ TPL  索引库, 收集了来自    15 个托管仓库中的     C/C++ TPL
                 的源代码存储库地址等信息. 基于此索引库, 构建了一个大规模                   C/C++ TPL  特征库, 包含  33 100  个  C/C++ TPL  中
                 的  30 047 290  个函数的代码特征, 为软件成分分析提供了坚实的数据基础.
                    (2) 准确而可靠的    TPL  成分检测能力. CAnalyzer 通过特征库预处理和多级阈值识别              TPL, 实现了精准的软件
   120   121   122   123   124   125   126   127   128   129   130