Why is unsafe.Sizeof considered unsafe?
Asked Answered
H

3

9

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.

Hawaiian answered 24/9, 2018 at 14:15 Comment(2)
Tip: if you want the size of some value, you may use reflect to avoid having to import and use unsafe, e.g. reflect.TypeOf(Foo{}).Size().Thant
There is indeed an issue by Rob Pike himself suggesting moving Sizeof out of unsafe. github.com/golang/go/issues/5602Organism
W
11

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)
}
Wennerholn answered 24/9, 2018 at 14:39 Comment(0)
B
3

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

Blur answered 24/9, 2018 at 14:19 Comment(0)
V
1

Go is a type safe programming language. It won't let you do stuff like this:

package main

type Foo = struct{ A string }
type Bar = struct{ B int }

func main() {
    var foo = &Foo{A: "Foo"}
    var bar = foo.(*Bar) // invalid operation!
    var bar2, ok = foo.(*Bar) // invalid operation!
}

Even if you use the type assertion with the special form that yields an additional boolean value; the compiler goes: haha, nope.

In a programming language like C though, the default is to assume that you are in charge. The program below will compile just fine.

typedef struct foo {
    const char* a_;
} foo;

typedef struct bar {
    int b_;
} bar;

int main() {
    foo f;
    f.a_ = "Foo";
    bar* b = &f; // warning: incompatible pointer types
    bar* b2 = (bar*)&f;
    return 0;
}

You get warnings for things that are probably wrong because people have learned over time that this is a common mistake but it's not stopping you. It's just emitting a warning.

Type safety just means that you can't make the same mistake C programmers have made a thousand times over already but it is neither unsafe nor wrong to use the the unsafe package or the C programming language. The unsafe package has just been named in opposition to type safety and it is precisely the right tool when you need to fiddle with the bits (manipulate the representation of things in memory; directly).

Vibratile answered 9/2, 2023 at 18:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.