icse 2021 https://arxiv.org/abs/2102.08543
项目地址 github

1. 背景

应用程序尽可能多地重用现有代码以节省成本。 现有代码通常采用libraries的形式,不断发展并可能引入不兼容的更改(例如,更改接口签名)。 滥用包含不兼容更改的库版本可能会导致应用程序失败。 我们将这些故障称为兼容性故障或 CFailures(compatibility failures)。image.png
CFailure 涉及三个角色:library developers、application developers 和 users。 如图 1 所示,库开发人员发布了两个包含不兼容更改的版本。 更改分为两种类型:向后不兼容更改(BIC)(例如删除接口)和前向不兼容更改(FIC)(例如添加接口)。

当发生不兼容的更改时,三个角色可以通过不同的解决方案来防止 CFailures:

  • 库开发人员可以撤消最新版本中的更改;
  • 应用开发者可以更新应用以适应变化;
  • 最终用户可以避免使用不兼容的库版本

现有的工具可以帮助用户选择正确库版本的项目 (DMS,dependency management systems)。示例包括

  • 基于 RPM 的 Linux 发行版中的 dnf
  • 基于 Debian 的 Linux 发行版中的 apt

然而,DMS 有几个实际限制:

  • DMS 需要应用程序或库开发人员的手动输入,存在出错的风险。
    • 例如,dnf 要求 application developers 指定所需库的版本范围。 apt 要求 library developers 维护库提供的符号列表。
  • 随着库的发展,开发人员提供的库版本可能会过时。
    • 例如,应用程序开发人员指定版本范围 libfoo>=1.0,之后发布 libfoo-2.0 并且向后不兼容 libfoo-1.0。 版本范围应该已经更新为2.0>libfoo>=1.0。
  • 开发人员可能不遵守 DMS 的要求。
    • 例如,apt 要求库不要破坏包中的向后兼容性,但库开发人员可能会无意中引入不兼容性,因为没有机制来保证这一要求。

为了解决 DMS 中的局限性,我们提出了一种新方法 DepOwl 来检测 DepBugs 并防止 CFailures。DepOwl 在二进制级别工作以检查库和应用程序之间的兼容性,而不是分析应用程序(例如编译器)源代码中的 API 使用情况。

2. 方法设计

方法总体设计思路如下
image.png

在本文中,我们重点检测 libraries applications 之间的二进制级别兼容性。 源代码级别的兼容性不能保证二进制级别的兼容性,例如修改类的虚拟表、更改函数参数的类型大小、更改枚举元素的值、更改结构字段的顺序、更改编译指令等。

image.png

2.1 Collecting Incompatible Changes

DepOwl的第一个组件将 library 作为输入,并收集其不兼容的更改。
ABI-Tracker : 一种用于检查C/C++库向后兼容性的工具。

然而,现有的工具主要关注向后兼容性问题。DepOwl将正向问题转化为反向问题
image.png

DepOwl应用了一个启发式规则:从Vold到Vnew的前向不兼容等价于从Vnew到Vold的后向不兼容,形式化为 :
image.png
image.png

2.2 Detecting Dependency Bugs

当 app 没有指定任何版本范围时,DepOwl 假定它接受所有版本。对于存储库中的每个应用程序包,DepOwl 会检测更改是否会导致 DepBug。 由于软件存储库可能包含数以万计的应用程序包,因此分析所有应用程序包非常耗时。 对此,DepOwl 将检测过程分为两个阶段:过滤阶段和检测阶段。

2.2.1 Filtering phase

  • DepOwl 过滤掉没有 IC 发生的库版本的应用程序包。
    • 例如,application 的使用的版本范围为 libfoo>=3.0,而IC发生在从 libfoo-1.0 ,libfoo-2.0的版本变更中。
  • DepOwl 过滤掉 IC 中没有使用更改元素的应用程序包。
    • 例如, library 为一个函数添加了一个参数,但这个函数并没有在 application 中使用。

2.2.2 Detecting phase

DepOwl 应用不同的规则来确定不兼容的版本。 比如ic在struct中添加字段时,DepOwl需要检查源代码中是否使用了附加字段。 当将 ic 检测返回值的类型从 void 更改为 non-void 时,DepOwl 需要检查该返回值是否在源代码中使用。
image.png
比如从zlib-1.2.6.1到zlib-1.2.7,函数get_crc_table的返回类型从long变成了int。 在unalz-0.65包的源码中,DepOwl找到“long *CRC_TABLE = get_crc_table();”,即返回类型匹配1.2.6.1版本。 因此,DepOwl 确定 1.2.7 是不兼容的版本。

2.3 Suggesting Incompatible Versions

在这一步中,DepOwl 检查的所有版本中更改元素的兼容性,并且在第二步中得到的不兼容版本的向后和向前兼容的任何版本都将被视为不兼容的版本。

3. 实验设计

实验评估三方面内容:

  • DepOwl 预测已知CFailures 的效果,即 recall of DepOwl
  • DepOwl 预测未知CFailures 的效果,即 precision of DepOwl
  • DepOwl 与现存方法的比较

3.1 recall of DepOwl

我们使用错误消息作为关键字,收集用户遇到的兼容性问题。
例如,当库删除一个符号时,应用程序将在运行时回显 “ symbol lookup error “。当 library 函数添加或删除参数时,编译器会在编译时提示 “too few/many parameter to function” 。

本文得到了 69 个问题涉及库中的不兼容更改

  • 38个问题涉及C/C++程序。
  • 23个问题的应用是发帖者提供的代码片段。
  • 其他问题涉及12个项目,包括来自不同领域的服务器(如Httpd、MongoDB)和客户端(如Eclipse、Qt)。

最后,本文使用 38 个C/C++程序的不兼容更改导致的CFailures 作为评估召回率的数据集。

结果显示,DepOwl 成功地为 38 个 C/C++ 相关问题中的 35 个建议了不兼容的版本。

3.2 precision of DepOwl

本文使用Ubuntu-19.10的前 1% 的 libraries 评估精确率的数据集,包含26 个不同的 libraries,涉及841 个版本。

评估结果:
DepOwl 检测到27,413 个 不兼容的更改,这些更改造成了77个 DepBugs(49个向后不兼容问题,28个向前不兼容问题)。在这77个DepBugs中,37个在后续版本中发生的撤销工作,24个在后续版本中被修复, 4个得到了原作者的确认,8个还在等待回复。

作者任务这个结果表明 DepOwl 可以在精度方面有效地检测现实世界的 DepBugs。

3.3 与现有方法的比较

image.png