Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is unsafe.Sizeof considered unsafe?

Tags:

go

unsafe

Consider the following:

import (
    "log"
    "unsafe"
)

type Foo struct {
    Bar int32
}

func main() {
    log.Println(int(unsafe.Sizeof(Foo{})))
}

Why is determining the size of a variable considered unsafe, and a part of the unsafe package? I don't understand why obtaining the size of any type is an unsafe operation, or what mechanism go uses to determine its size that necessitates this.

I would also love to know if there are any alternatives to the unsafe package for determining size of a known struct.

like image 376
Josh Avatar asked Sep 24 '18 14:09

Josh


2 Answers

Because in Go if you need to call sizeof, it generally means you're manipulating memory directly, and you should never need to do that.

If you come from the C world, you'll probably most often have used sizeof together with malloc to create a variable-length array - but this should not be needed in Go, where you can simply make([]Foo, 10). In Go, the amount of memory to be allocated is taken care of by the runtime.

You should not be afraid of calling unsafe.Sizeof where it really makes sense - but you should ask yourself whether you actually need it.

Even if you're using it for, say, writing a binary format, it's generally a good idea to calculate by yourself the number of bytes you need, or if anything generate it dynamically using reflect:

  • calling unsafe.Sizeof on a struct will also include the number of bytes added in for padding.
  • calling it on dynamically-sized structures (ie. slices, strings) will yield the length of their headers - you should call len() instead.

Using unsafe on a uintptr, int or uint to determine whether you're running on 32-bit or 64-bit? You can generally avoid that by specifying int64 where you actually need to support numbers bigger than 2^31. Or, if you really need to detect that, you have many other options, such as build tags or something like this:

package main

import (
    "fmt"
)

const is32bit = ^uint(0) == (1 << 32) - 1

func main() {
    fmt.Println(is32bit)
}
like image 84
morganbaz Avatar answered Nov 20 '22 09:11

morganbaz


From the looks of the unsafe package the methods don't use go's type safety for their operations.

https://godoc.org/unsafe

Package unsafe contains operations that step around the type safety of Go programs.

Packages that import unsafe may be non-portable and are not protected by the Go 1 compatibility guidelines.

So from the sounds of it the unsafe-ness is in the kind of code being provided, not necessarily from calling it in particular

like image 26
Peter Mellett Avatar answered Nov 20 '22 09:11

Peter Mellett