Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

unsafe 包的使用 #8

Closed
GuoYuefei opened this issue Jun 22, 2020 · 0 comments
Closed

unsafe 包的使用 #8

GuoYuefei opened this issue Jun 22, 2020 · 0 comments
Assignees
Labels
golang 有关golang, 颜色取自官网

Comments

@GuoYuefei
Copy link
Owner

unsafe 包的使用

go指针的限制

  1. go的指针不能进行数学运算
  2. 不同类型的指针不能相互转换
  3. 不同类型的指针不能使用 == 或 != 比较
  4. 不同类型的指针变量不能相互赋值

unsafe 包提供了 2 点重要的能力

  1. 任何类型的指针和 unsafe.Pointer 可以相互转换。
  2. uintptr 类型和 unsafe.Pointer 可以相互转换。

ps. uintptr 并没有指针的语义,意思就是 uintptr 所指向的对象会被 gc 无情地回收。而 unsafe.Pointer 有指针语义,可以保护它所指向的对象在“有用”的时候不会被垃圾回收。

unsafe 包可以做什么坏事

1.绕过私有成员的限制

可以通过unsafe包绕过私有属性限制对私有属性读写。

package A

type A struct {
	name string
	age int
    mark bool
}
package main

import (
    "A"
	"fmt"
    "unsafe"
)

func main() {
    a := A.A{}
    fmt.Println(a)
    
    name := (*string)(unsafe.Pointer(&p))
    age := (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(&p)) + unsafe.Sizeof(string(""))))
    mark := (*bool)(unsafe.Pointer(uintptr(unsafe.Pointer(&p)) + unsafe.Sizeof(string("")) + unsafe.Sizeof(0)))
    
    *name = "A"
    *age = 20
    *mark = false
    
    // output {A 20 false}
    fmt.Println(a)
}

2.通过伪造快速对私有属性更改

这边以内置类型slice为例,可以参考slice的源码。

ps. 与本主题无关的提示: make得到的slice是实体,make得到的map是指针。

package main

import (
	"fmt"
	"unsafe"
)

// 也可以使用小技巧,构造一个和 slice 一样的结构体来解析或操作切片
type slice struct {
	arrptr unsafe.Pointer
	l int
	c int
}

func main() {
	a := []int{1,2}
	a = append(a, 3)
	length := (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(&a)) + unsafe.Sizeof(unsafe.Pointer(&a))))

	ca := (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(&a)) + unsafe.Sizeof(unsafe.Pointer(&a)) + unsafe.Sizeof(int(0))))

	fmt.Println(*length, *ca)

	*length = *length + 1				// + 1024 没问题, 只要在保护的内存段中就行
	//a = append(a, 4)
	fmt.Println(a, *length, *ca)

	s := *(*slice)(unsafe.Pointer(&a))

	fmt.Println(s)
	fmt.Printf("[%d, %d, %d, %d]\n", *(*int)(s.arrptr), *(*int)(unsafe.Pointer(uintptr(s.arrptr) + unsafe.Sizeof(int(0)))),
		*(*int)(unsafe.Pointer(uintptr(s.arrptr) + 2*unsafe.Sizeof(int(0)))),
		*(*int)(unsafe.Pointer(uintptr(s.arrptr) + 3*unsafe.Sizeof(int(0)))),
		)

}
@GuoYuefei GuoYuefei added the golang 有关golang, 颜色取自官网 label Jun 22, 2020
@GuoYuefei GuoYuefei self-assigned this Jun 22, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
golang 有关golang, 颜色取自官网
Projects
None yet
Development

No branches or pull requests

1 participant