Page 24 - 《软件学报》2024年第6期
P. 24
2600 软件学报 2024 年第 35 卷第 6 期
者修复了重构后的逃逸算法上的 Bug.
代码 5. DBI-Go 发现的新逃逸算法出错的例子 1.
1. package nomain
2. type prefixError struct{s string}
3. func New(f string, x ...interface{}) error {
4. // 误将字面量 prefixError{}分配到栈上
5. return & prefixError{}
6. }
7. func (e *prefixError) Error() string {
8. return “1” + e.s
9. }
代码 6. DBI-Go 发现的新逃逸算法出错的例子 2.
1. var gm map[string]interface{}
2.
3. func Test() {
4. // 误将 b 分配到栈上
5. var b int
6. gm[“1”] = & b
7. }
4.2 额外开销
4.2.1 额外运行时开销 4 (2.8%). 产生额外的
相比于只需在运行前执行一次的静态分析和初始化, 插桩的回调函数带来的额外运行时开销在反复执行时会
占据主要比例, 这些额外的运行时开销主要包括以下几部分: (1) 调用回调函数的开销; (2) 获取 Go 的运行时信息
的开销; (3) 利用规则 1 和规则 2 进行运行时验证的开销. 为了了解这些额外运行时开销的影响, 我们使用第 4.1
节中所述的 Go 标准库和编译工具链中的 277 个包中的测例进行了测试. 最终, 记录了插桩的回调函数带来的额
外运行时开销相比于直接执行时所花费的开销的比值. 为了表述方便, 在下文使用 R c/o 表示额外的运行时开销相
比于直接执行时所花费的开销的比值.
为了了解 R c/ 的分布, 对得到的额外开销数据使用了 KDE (kernel density estimation, 核密度估计, 一种用于估
o
计随机变量的概率密度函数的非参数方法) [40, 41] 估计了 R c/ 在这 277 个包中的分布密度, 如后文图 10 所示. 该曲
o
线的波峰在 R c/ 约为 0.25 处达到, 且绝大多数的额外开销相比于原生开销的比值均小于 2 (93.3%) 只有在极少数
o
store 密集型的程序中该比值才会大于 2 倍运行时开销是可以承受的.
4.2.2 额外初始化开销
在前文中提到, 由于初始化部分只需在运行前执行一次, 因此其相比于可以反复执行的运行时开销可以忽略.
但用于初始化的该部分开销在使用时也会对总时间造成影响, 因此对该部分开销的测试也是必要的. 额外的初始
化开销包括以下几部分时间: (1) Pin 加载用户二进制的开销; (2) 反汇编的开销; (3) 使用静态分析, 利用 Go 的写屏
障机制恢复 Go store 语义的开销. 使用和第 4.2.1 节相同的测试集和测试方式, 通过记录额外的初始化开销与原生
开销的比值, 并使用 KDE 估计分布密度, 可以得到图 11. 为了表述方便, 在下文使用 R i/ 来表示额外的初始化开
o
销相比于原生开销的比值.
图 11 有两波波峰, 第 1 波大约在 R i/ 为 o 4 处, 另一波对应的 R i/o 则超过了 100. 相比于原生开销 100 倍的额外