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

all: use reflect.StringHeader and reflect.SliceHeader for pointer conversions #37805

Closed
smasher164 opened this issue Mar 11, 2020 · 22 comments
Closed
Labels
FrozenDueToAge help wanted NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made.
Milestone

Comments

@smasher164
Copy link
Member

smasher164 commented Mar 11, 2020

As @mdempsky states in #19367 (comment),

It's not guaranteed that you can convert a pointer to a slice to a pointer to any other struct type except reflect.SliceHeader.

Therefore, the following conversions in the golang subrepos (except runtime and reflect) should be modified to use reflect.StringHeader and reflect.SliceHeader when converting between an unsafe.Pointer and a string/slice.

@smasher164 smasher164 changed the title all: use reflect.StringHeader and reflect.SliceHeader for pointer conversions all: use reflect.StringHeader and reflect.SliceHeader for unsafe.Pointer conversions Mar 11, 2020
@smasher164 smasher164 added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Mar 11, 2020
@smasher164 smasher164 changed the title all: use reflect.StringHeader and reflect.SliceHeader for unsafe.Pointer conversions all: use reflect.StringHeader and reflect.SliceHeader for pointer conversions Mar 11, 2020
@bcmills bcmills added this to the Backlog milestone Mar 11, 2020
@mdempsky
Copy link
Member

Thanks. Confirmed, those are all misuses of unsafe.Pointer.

@mdempsky mdempsky added the NeedsFix The path to resolution is known, but the work has not been done. label Mar 11, 2020
@gopherbot gopherbot removed the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Mar 11, 2020
@twmb
Copy link
Contributor

twmb commented Mar 11, 2020

Don't most of these fall under unsafe rule (1), and the uintptr ones fall under managing syscall stuff directly?

@mdempsky
Copy link
Member

Yes, the last three examples are safe today (on gc and gccgo, at least) under rule 1, but might not be safe in the future. As reflect.SliceHeader's docs warn: "its representation may change in a later release." Using reflect.SliceHeader is the future proof solution.

The first two don't involve direct uses of syscall.Syscall, so rule 4 is inapplicable.

But that does make me note that the first example is within package syscall, which isn't allowed to depend on package reflect. :/

@twmb
Copy link
Contributor

twmb commented Mar 11, 2020

I thought I remembered a proposal about adding equivalent unsafe.StringHeader and unsafe.SliceHeader types, but I can't find it. But, that idea may be worthwhile to address the syscall issue, as well as to allow users of just StringHeader/SliceHeader to avoid importing the reflect package.

@smasher164
Copy link
Member Author

smasher164 commented Mar 12, 2020

Can't syscall access runtime.slice instead of reflect.SliceHeader? It already linknames in runtime functions.

Edit: @twmb You are referring to #19367 which forked off into this issue to fix pre-existing conversions.

@mdempsky
Copy link
Member

@smasher164 linkname only works for functions and variables; not types.

@smasher164
Copy link
Member Author

@smasher164 linkname only works for functions and variables; not types.

Right, so we would need a runtime function similar to func newslice() unsafe.Pointer that syscall would call to turn it into *[]byte. Although, that might be too heavyweight of an addition to support one package.

@bcmills
Copy link
Contributor

bcmills commented Mar 12, 2020

Seems like syscall could use the usual “convert to *[reallyBig]byte and then slice down to size” pattern, but for portability we'll presumably need build constraints for the definition of reallyBig (see #13656 (comment)).

@bcmills
Copy link
Contributor

bcmills commented Mar 12, 2020

(More supporting evidence for #19367? CC @ianlancetaylor @griesemer)

@gopherbot
Copy link

Change https://golang.org/cl/230557 mentions this issue: x/sys: use reflect.SliceHeader for ptr conversion

@tklauser
Copy link
Member

Given the comments regarding the syscall package, I think we also want to avoid importing reflect in x/sys/unix for which https://golang.org/cl/230557 was sent. Copying my comment from there:

[...] I'd really like to avoid importing the quite heavy-weight reflect package just for the reflect.SliceHeader type. The issue also mentions special constraints regarding the syscall package. Could we maybe use something like proposed by Bryan in #37805 (comment) for this package as well, given it's closely related to package syscall?

@smasher164 smasher164 added the NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made. label Apr 28, 2020
@gopherbot gopherbot removed the NeedsFix The path to resolution is known, but the work has not been done. label Apr 28, 2020
@mdempsky
Copy link
Member

Yeah, I forgot that package syscall can't import package reflect, and that x/sys probably doesn't want to either. Using the (*[big]T)[:x:x] idiom seems reasonable in those cases.

The two instances in cmd should be reasonable for package reflect though.

@keyan
Copy link
Contributor

keyan commented Apr 28, 2020

After reading the linked discussion in #13656, it still isn't clear to me if the technique explained there and described in https://github.com/golang/go/wiki/cgo#turning-c-arrays-into-go-slices is platform independent?

Ian mentioned that big == 50 is safe? #13656 (comment)

But for the case in syscall_unix's Mmap we are mapping up to length int bytes so on 64-bit systems isn't it possible 1<<50 is not large enough?

@smasher164
Copy link
Member Author

The two instances in cmd should be reasonable for package reflect though.

Since the old linker is moved, I've edited the description to point the second instance in cmd to cmd/oldlink/internal/objfile.

@mdempsky
Copy link
Member

mdempsky commented Apr 28, 2020

After reading the linked discussion in #13656, it still isn't clear to me if the technique explained there and described in https://github.com/golang/go/wiki/cgo#turning-c-arrays-into-go-slices is platform independent?

The correct value of big is unfortunately platform-dependent. See the value of arch.MAXWIDTH in cmd/compile/internal/$ARCH/galign.go. (You then have to divide down by sizeof(T).)

But for the case in syscall_unix's Mmap we are mapping up to length int bytes so on 64-bit systems isn't it possible 1<<50 is not large enough?

The amd64 ISA supports 64-bit pointers, but today's implementations (i.e., CPUs) only support 48-bits of addressable page tables.

Edit: It seems like this is no longer true: "The 5-level paging scheme supports a Linear Address space up to 57 bits and a physical address space up to 52 bits". https://en.wikipedia.org/wiki/Ice_Lake_(microprocessor)

@keyan
Copy link
Contributor

keyan commented Apr 28, 2020

Okay thanks for the clarification. I'll take another pass tonight.

For the cases in cmd/internal and cmd/oldlink using MAXWIDTH seems straightforward as the package global thearch can be used. Not sure how/if architecture can be identified for the open CL I have in sys, or how/if build directives can be used to accomplish this (as Bryan noted above).

@mdempsky
Copy link
Member

I don't think you can use MAXWIDTH as it's a variable, not a constant. It's also the maximum width of the target architecture, whereas for the array type expressions you need the maximum width of the host architecture.

@bcmills
Copy link
Contributor

bcmills commented Apr 29, 2020

Another option might be to define a separate struct, and rely on a regression test to ensure that its layout remains compatible with reflect.SliceHeader. That way only the test itself needs to depend on reflect, but we don't need a bunch of platform-specific build-constraint shenanigans to make it portable.

For example, perhaps something like: https://play.golang.org/p/13IbIZOGFFl
(unpack locally using txtar -x).

@mdempsky
Copy link
Member

@bcmills Thanks, I hate it.

But seriously, that seems to me like it should work, and it's probably the least invasive solution while we wait for #19367 and/or generics.

@gopherbot
Copy link

Change https://golang.org/cl/231177 mentions this issue: unix: use a type equivalent to reflect.SliceHeader to manipulate slices

gopherbot pushed a commit to golang/sys that referenced this issue Apr 30, 2020
The regression test included in this change verifies that the type is,
in fact, equivalent, while allowing the actual header definitions to
avoid importing the (relatively heavy) "reflect" package itself.

This change is loosely based on Keyan Pishdadian's draft in CL 230557.

For golang/go#37805

Change-Id: I998c69cdeb852154cd66ab5fdaa542a6f19666a2
Reviewed-on: https://go-review.googlesource.com/c/sys/+/231177
Run-TryBot: Bryan C. Mills <bcmills@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Tobias Klauser <tobias.klauser@gmail.com>
@gopherbot
Copy link

Change https://golang.org/cl/231223 mentions this issue: internal/unsafeheader: consolidate stringHeader and sliceHeader declarations into an internal package

@keyan
Copy link
Contributor

keyan commented Apr 30, 2020

@bcmills Thanks for all the suggestions. Unfortunately this felt a little over my head for my second issue, but reading your CL has been very educational. Thanks!

@bcmills bcmills modified the milestones: Backlog, Go1.15 May 1, 2020
xujianhai666 pushed a commit to xujianhai666/go-1 that referenced this issue May 21, 2020
…rations into an internal package

The new package "internal/unsafeheader" depends only on "unsafe", and
provides declarations equivalent to reflect.StringHeader and
reflect.SliceHeader but with Data fields of the proper unsafe.Pointer
type (instead of uintptr).

Unlike the types it replaces, the "internal/unsafeheader" package has
a regression test to ensure that its header types remain equivalent to
the declarations provided by the "reflect" package.

Since "internal/unsafeheader" has almost no dependencies, it can be
used in other low-level packages such as "syscall" and "reflect".

This change is based on the corresponding x/sys change in CL 231177.

Fixes golang#37805
Updates golang#19367

Change-Id: I7a6d93ef8dd6e235bcab94e7c47270aad047af31
Reviewed-on: https://go-review.googlesource.com/c/go/+/231223
Reviewed-by: Ian Lance Taylor <iant@golang.org>
@golang golang locked and limited conversation to collaborators May 1, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge help wanted NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made.
Projects
None yet
Development

No branches or pull requests

7 participants