验证golang中unsafe包不安全

栏目: Go · 发布时间: 5年前

内容简介:在go中,uintptr不能持有对象,unsafe包不安全,但是我之前一直没有时间验证,今天写了段代码验证了一下。根据逃逸分析可以看出来f和f2这两个函数中的d变量分别分配在哪里:可以看出来在函数f中,d逃逸到堆上;但是在函数f2中,d没有发生逃逸,uintptr没有持有对象。

go 中,uintptr不能持有对象,unsafe包不安全,但是我之前一直没有时间验证,今天写了段代码验证了一下。

代码

package main

import (
	"fmt"
	"unsafe"
)

func main() {
	a := f()
	b := f2()
	fmt.Println(a)
	fmt.Println(b)
}

//go:noinline
func f() unsafe.Pointer {
	d := 1
	p := unsafe.Pointer(&d)
	return p
}

//go:noinline
func f2() uintptr {
	d := 1
	p := uintptr(unsafe.Pointer(&d))
	return p
}

逃逸分析

根据逃逸分析可以看出来f和f2这两个函数中的d变量分别分配在哪里:

编译参数方法

$ go build -gcflags '-m -m' unsafe.go
# command-line-arguments
./unsafe.go:16:6: cannot inline f: marked go:noinline
./unsafe.go:23:6: cannot inline f2: marked go:noinline
./unsafe.go:8:6: cannot inline main: function too complex: cost 260 exceeds budget 80
./unsafe.go:11:13: inlining call to fmt.Println func(...interface {}) (int, error) { return fmt.Fprintln(io.Writer(os.Stdout), fmt.a...) }
./unsafe.go:12:13: inlining call to fmt.Println func(...interface {}) (int, error) { return fmt.Fprintln(io.Writer(os.Stdout), fmt.a...) }
./unsafe.go:18:22: &d escapes to heap
./unsafe.go:18:22: 	from p (assigned) at ./unsafe.go:18:4
./unsafe.go:18:22: 	from ~r0 (return) at ./unsafe.go:19:2
./unsafe.go:17:2: moved to heap: d
./unsafe.go:25:30: f2 &d does not escape
./unsafe.go:11:13: a escapes to heap
./unsafe.go:11:13: 	from ~arg0 (assign-pair) at ./unsafe.go:11:13
./unsafe.go:11:13: io.Writer(os.Stdout) escapes to heap
./unsafe.go:11:13: 	from io.Writer(os.Stdout) (passed to call[argument escapes]) at ./unsafe.go:11:13
./unsafe.go:12:13: io.Writer(os.Stdout) escapes to heap
./unsafe.go:12:13: 	from io.Writer(os.Stdout) (passed to call[argument escapes]) at ./unsafe.go:12:13
./unsafe.go:12:13: b escapes to heap
./unsafe.go:12:13: 	from ~arg0 (assign-pair) at ./unsafe.go:12:13
./unsafe.go:12:13: 	from []interface {} literal (slice-literal-element) at ./unsafe.go:12:13
./unsafe.go:12:13: 	from fmt.a (assigned) at ./unsafe.go:12:13
./unsafe.go:12:13: 	from *fmt.a (indirection) at ./unsafe.go:12:13
./unsafe.go:12:13: 	from fmt.a (passed to call[argument content escapes]) at ./unsafe.go:12:13
./unsafe.go:11:13: main []interface {} literal does not escape
./unsafe.go:12:13: main []interface {} literal does not escape
<autogenerated>:1: os.(*File).close .this does not escape

可以看出来在函数f中,d逃逸到堆上;但是在函数f2中,d没有发生逃逸,uintptr没有持有对象。

汇编

再来看看汇编的结果:

$ go tool compile -S unsafe.go | grep unsafe.go:24
	0x000e 00014 (unsafe.go:24)	PCDATA	$2, $0
	0x000e 00014 (unsafe.go:24)	PCDATA	$0, $0
	0x000e 00014 (unsafe.go:24)	MOVQ	$1, "".d(SP)
$ go tool compile -S unsafe.go | grep unsafe.go:17
	0x001d 00029 (unsafe.go:17)	PCDATA	$2, $1
	0x001d 00029 (unsafe.go:17)	PCDATA	$0, $0
	0x001d 00029 (unsafe.go:17)	LEAQ	type.int(SB), AX
	0x0024 00036 (unsafe.go:17)	PCDATA	$2, $0
	0x0024 00036 (unsafe.go:17)	MOVQ	AX, (SP)
	0x0028 00040 (unsafe.go:17)	CALL	runtime.newobject(SB)
	0x002d 00045 (unsafe.go:17)	PCDATA	$2, $1
	0x002d 00045 (unsafe.go:17)	MOVQ	8(SP), AX
	0x0032 00050 (unsafe.go:17)	MOVQ	$1, (AX)

可以看出来,结果也是一样的,f中的d调用了newobject,但是f2中没有。

结论

所以为什么说unsafe包不安全呢,原因之一就是因为go不保证地址一定是有效的,当然还有其它的原因,有时间再验证分享。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

失业的程序员

失业的程序员

沈逸 / 2014-5-1 / 39.00元

这是一个程序员从失业到自行创业的奋斗历程,虽然囧事连连、过程曲折,却充满了趣味。本书以作者的真实创业经历为主线,文字幽默诙谐,情节生动真实,包括了招聘、团队管理和用户公关,以及技术架构设计、核心代码编写、商务谈判、项目运作等场景经验。 从初期的创业伙伴、领路人,到商业竞争对手,各种复杂的关系在各个关键时刻却都发生了意想不到的逆转。在历经千辛万苦,眼看快要成功时,主人公却几乎再次失业。 ......一起来看看 《失业的程序员》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具