golang/go

proposal: unsafe: allow Offsetof slice/array index expression

rsc opened this issue · 7 comments

rsc commented

In #40481 (comment)_, @kortschak wrote:

Arguably in the same family of operations is the ability to obtain a memory offset for indexed items in a slice or array (#12445). Could this be considered in package of additions (or nearby)?

We could do this with unsafe.Offsetof(x[5]) to evaluate to 5*unsafe.Sizeof(x[0]), but we'd also have to consider unsafe.Offsetof(x[i]), in which case the result of Offsetof would not be a constant in certain cases.

rsc commented

@kortschak can you comment a bit more about when you would use this functionality and how much it would help versus just writing the multiplication?

Are arrays in Go always packed, and never aligned with padding? I'm surprised that unsafe.Offsetof(x[5]) is just 5*unsafe.Sizeof(x[0]). That's where offsetof for arrays could be useful to future proof a program.

@beoran I think unsafe.Sizeof includes padding for alignment. https://play.golang.org/p/xVWy-kfXIUK

Are arrays in Go always packed, and never aligned with padding?

In practice, sizeof([N]T) is always exactly N * sizeof(T).

However, currently the Go spec doesn't guarantee that. It only guarantees that alignof([N]T) == alignof(T).

@rsc, the original issue is #12445 which goes into the details. It's not that I want to be able to find the offset of elements from the start of the slice/array (this would be best done with uintptr(idx)*unsafe.Sizeof(a[0]). What I want is someway to calculate the offset between elements that are potentially in the same slice but with different names.

Where this is used is here to be consumed e.g. here. What we have works at the moment, but we have to guard it with extensive tests because the behaviour is not specified (although in in the case that we look at it should never be wrong when we need it unless memory moves are interleaved into the expression in offset.go linked above - though a compiler bug has broken us in the past).

rsc commented

I obviously misunderstood what your comment was about. The Offsetof operation I described above does not help you decide overlap in any way. What you are using is fine and not likely to be broken any time soon. (Breaking it would imply a read barrier inserted mid-statement, which I can't see happening honestly ever, but certainly not any time soon.)
Note that we have the same check in go/src/crypto/internal/subtle/aliasing.go.

I also can't imagine a situation where we'd want to violate unsafe.Sizeof([N]T) = N*unsafe.Sizeof(T)
and more generally that the size allocated by make([]T, N) is also N*unsafe.Sizeof(T).
That is, I can't imagine that we'd ever violate that Sizeof(T) is a multiple of Alignof(T).

Given that (1) this issue I filed wasn't what you were asking for and (2) this issue I filed doesn't seem any harder than the multiplication, and the multiplication avoids the const problems, it seems like this issue should be declined.

Retracting.

@rsc, Thank you for the pointer to crypto/internal/subtle; it's good to know we are not standing out on a limb alone.