Page 17 - 《软件学报》2024年第6期
P. 17
陈金宝 等: DBI-Go: 动态插桩定位 Go 二进制的非法内存引用 2593
S = codeS (code(s l )),G 1 = codeG(code(s l )) ∃G 2 , addr ∈ S∧addr dst ∈ G 2 .S∧G 1 , G 2
(5)
illegal(s l )
由于 Go 的地址空间由 Go 堆、全局数据区, 以及所有 Goroutine 的栈组成, 因此, 一个对象若不在当前
Goroutine 栈中, 则要么在 Go 堆中, 要么在全局数据区, 要么在其他 Goroutine 栈中. 即:
S = codeS (code(s l )),G 1 = codeG(code(s l ))
(6)
addr dst < S ⇐⇒ addr dst ∈ GH∨addr dst ∈ GG∨(∃G 2 , addr dst ∈ G 2 .S∧G 1 , G 2 )
结合公式 (6), 可将公式 (3)、公式 (4)、公式 (5) 合为一个式子, 此时便得到判定违反逃逸不变式的第 1 条规
则, 该规则揭示了栈对象地址被写入当前 Goroutine 栈之外的内存使用违例情况.
规则 1. 栈对象地址被写入当前 Goroutine 栈之外的违例判别.
s l : store addr dst , addr
S = codeS (code(s l )) addr ∈ S∧addr dst < S
.
illegal(s l )
该规则表示将当前 Goroutine 栈的对象地址存入当前 Goroutine 栈外, 导致栈外对象引用栈内对象是不符合
Go 的逃逸不变式要求的, 如图 5(a) 所示.
stack.hi 高地址 stack.hi 高地址
l
深栈帧
栈 栈对象
栈帧 增 栈
l
长 浅栈帧 增
方 长
栈外对象 栈对象 向 栈对象 方
l 向
rsp
rsp
stack.lo 低地址 stack.lo 低地址
Goroutine
Goroutine illegal(s l )
栈
栈
(a) 栈外对象指向栈对象 (b) 较深栈帧栈对象指向较浅栈帧栈对象
图 5 规则 1 及规则 2 示意
• 将栈对象地址写入当前 Goroutine 栈内的违例情况. 在同一个 Goroutine 栈中, 不同栈对象生命期亦有差距, 比
如作用域较浅的栈对象比作用域深的栈对象生命期长, 较深函数栈帧中的栈对象比较浅函数栈帧中的栈对象生命期
长. 由于在二进制中已经难以看到源代码层级的作用域, 此处只能通过栈对象所在函数栈帧的深浅来判断其生命期,
认为较深栈帧栈对象生命期更长, 如图 5(b) 所示. 由此可以引出判定违反逃逸不变式的第 2 条判定规则, 即规则 2.
规则 2. 栈对象地址被写入当前 Goroutine 栈内的违例判别.
s l : store addr dst , addr
S = codeS (code(s l )) addr ∈ S∧addr dst ∈ S∧ fd(addr) < fd(addr dst )
.
3 DBI-Go 的设计与实现
本节将介绍 DBI-Go, 一款用于识别 Go 二进制中写入指针的 store 指令并在运行时验证其是否违反 Go 逃逸
不变式的工具的具体设计与实现.
3.1 设计目标和设计思路
DBI-Go 的设计目标主要包括以下几点.