验证golang中unsafe包不安全

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

内容简介:在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不保证地址一定是有效的,当然还有其它的原因,有时间再验证分享。


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

查看所有标签

猜你喜欢:

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

Designing Web Navigation

Designing Web Navigation

James Kalbach / O'Reilly Media / 2007-8-15 / USD 49.99

Thoroughly rewritten for today's web environment, this bestselling book offers a fresh look at a fundamental topic of web site development: navigation design. Amid all the changes to the Web in the pa......一起来看看 《Designing Web Navigation》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

随机密码生成器
随机密码生成器

多种字符组合密码

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具