diff --git a/internal/unsafeheader/unsafeheader.go b/internal/unsafeheader/unsafeheader.go deleted file mode 100644 index e07899b9..00000000 --- a/internal/unsafeheader/unsafeheader.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2020 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package unsafeheader contains header declarations for the Go runtime's -// slice and string implementations. -// -// This package allows x/sys to use types equivalent to -// reflect.SliceHeader and reflect.StringHeader without introducing -// a dependency on the (relatively heavy) "reflect" package. -package unsafeheader - -import ( - "unsafe" -) - -// Slice is the runtime representation of a slice. -// It cannot be used safely or portably and its representation may change in a later release. -type Slice struct { - Data unsafe.Pointer - Len int - Cap int -} - -// String is the runtime representation of a string. -// It cannot be used safely or portably and its representation may change in a later release. -type String struct { - Data unsafe.Pointer - Len int -} diff --git a/internal/unsafeheader/unsafeheader_test.go b/internal/unsafeheader/unsafeheader_test.go deleted file mode 100644 index 2793c1fa..00000000 --- a/internal/unsafeheader/unsafeheader_test.go +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2020 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package unsafeheader_test - -import ( - "bytes" - "reflect" - "testing" - "unsafe" - - "golang.org/x/sys/internal/unsafeheader" -) - -// TestTypeMatchesReflectType ensures that the name and layout of the -// unsafeheader types matches the corresponding Header types in the reflect -// package. -func TestTypeMatchesReflectType(t *testing.T) { - t.Run("Slice", func(t *testing.T) { - testHeaderMatchesReflect(t, unsafeheader.Slice{}, reflect.SliceHeader{}) - }) - - t.Run("String", func(t *testing.T) { - testHeaderMatchesReflect(t, unsafeheader.String{}, reflect.StringHeader{}) - }) -} - -func testHeaderMatchesReflect(t *testing.T, header, reflectHeader interface{}) { - h := reflect.TypeOf(header) - rh := reflect.TypeOf(reflectHeader) - - for i := 0; i < h.NumField(); i++ { - f := h.Field(i) - rf, ok := rh.FieldByName(f.Name) - if !ok { - t.Errorf("Field %d of %v is named %s, but no such field exists in %v", i, h, f.Name, rh) - continue - } - if !typeCompatible(f.Type, rf.Type) { - t.Errorf("%v.%s has type %v, but %v.%s has type %v", h, f.Name, f.Type, rh, rf.Name, rf.Type) - } - if f.Offset != rf.Offset { - t.Errorf("%v.%s has offset %d, but %v.%s has offset %d", h, f.Name, f.Offset, rh, rf.Name, rf.Offset) - } - } - - if h.NumField() != rh.NumField() { - t.Errorf("%v has %d fields, but %v has %d", h, h.NumField(), rh, rh.NumField()) - } - if h.Align() != rh.Align() { - t.Errorf("%v has alignment %d, but %v has alignment %d", h, h.Align(), rh, rh.Align()) - } -} - -var ( - unsafePointerType = reflect.TypeOf(unsafe.Pointer(nil)) - uintptrType = reflect.TypeOf(uintptr(0)) -) - -func typeCompatible(t, rt reflect.Type) bool { - return t == rt || (t == unsafePointerType && rt == uintptrType) -} - -// TestWriteThroughHeader ensures that the headers in the unsafeheader package -// can successfully mutate variables of the corresponding built-in types. -// -// This test is expected to fail under -race (which implicitly enables -// -d=checkptr) if the runtime views the header types as incompatible with the -// underlying built-in types. -func TestWriteThroughHeader(t *testing.T) { - t.Run("Slice", func(t *testing.T) { - s := []byte("Hello, checkptr!")[:5] - - var alias []byte - hdr := (*unsafeheader.Slice)(unsafe.Pointer(&alias)) - hdr.Data = unsafe.Pointer(&s[0]) - hdr.Cap = cap(s) - hdr.Len = len(s) - - if !bytes.Equal(alias, s) { - t.Errorf("alias of %T(%q) constructed via Slice = %T(%q)", s, s, alias, alias) - } - if cap(alias) != cap(s) { - t.Errorf("alias of %T with cap %d has cap %d", s, cap(s), cap(alias)) - } - }) - - t.Run("String", func(t *testing.T) { - s := "Hello, checkptr!" - - var alias string - hdr := (*unsafeheader.String)(unsafe.Pointer(&alias)) - hdr.Data = (*unsafeheader.String)(unsafe.Pointer(&s)).Data - hdr.Len = len(s) - - if alias != s { - t.Errorf("alias of %q constructed via String = %q", s, alias) - } - }) -} diff --git a/windows/security_windows.go b/windows/security_windows.go index d414ef13..26be94a8 100644 --- a/windows/security_windows.go +++ b/windows/security_windows.go @@ -7,8 +7,6 @@ package windows import ( "syscall" "unsafe" - - "golang.org/x/sys/internal/unsafeheader" ) const ( @@ -1341,21 +1339,14 @@ func (selfRelativeSD *SECURITY_DESCRIPTOR) copySelfRelativeSecurityDescriptor() sdLen = min } - var src []byte - h := (*unsafeheader.Slice)(unsafe.Pointer(&src)) - h.Data = unsafe.Pointer(selfRelativeSD) - h.Len = sdLen - h.Cap = sdLen - + src := unsafe.Slice((*byte)(unsafe.Pointer(selfRelativeSD)), sdLen) + // SECURITY_DESCRIPTOR has pointers in it, which means checkptr expects for it to + // be aligned properly. When we're copying a Windows-allocated struct to a + // Go-allocated one, make sure that the Go allocation is aligned to the + // pointer size. const psize = int(unsafe.Sizeof(uintptr(0))) - - var dst []byte - h = (*unsafeheader.Slice)(unsafe.Pointer(&dst)) alloc := make([]uintptr, (sdLen+psize-1)/psize) - h.Data = (*unsafeheader.Slice)(unsafe.Pointer(&alloc)).Data - h.Len = sdLen - h.Cap = sdLen - + dst := unsafe.Slice((*byte)(unsafe.Pointer(&alloc[0])), sdLen) copy(dst, src) return (*SECURITY_DESCRIPTOR)(unsafe.Pointer(&dst[0])) } diff --git a/windows/svc/mgr/mgr.go b/windows/svc/mgr/mgr.go index c2dc8701..4449161a 100644 --- a/windows/svc/mgr/mgr.go +++ b/windows/svc/mgr/mgr.go @@ -17,7 +17,6 @@ import ( "unicode/utf16" "unsafe" - "golang.org/x/sys/internal/unsafeheader" "golang.org/x/sys/windows" ) @@ -199,12 +198,7 @@ func (m *Mgr) ListServices() ([]string, error) { if servicesReturned == 0 { return nil, nil } - - var services []windows.ENUM_SERVICE_STATUS_PROCESS - hdr := (*unsafeheader.Slice)(unsafe.Pointer(&services)) - hdr.Data = unsafe.Pointer(&buf[0]) - hdr.Len = int(servicesReturned) - hdr.Cap = int(servicesReturned) + services := unsafe.Slice((*windows.ENUM_SERVICE_STATUS_PROCESS)(unsafe.Pointer(&buf[0])), int(servicesReturned)) var names []string for _, s := range services { diff --git a/windows/svc/mgr/recovery.go b/windows/svc/mgr/recovery.go index 32145199..f7d13bbd 100644 --- a/windows/svc/mgr/recovery.go +++ b/windows/svc/mgr/recovery.go @@ -13,7 +13,6 @@ import ( "time" "unsafe" - "golang.org/x/sys/internal/unsafeheader" "golang.org/x/sys/windows" ) @@ -70,12 +69,7 @@ func (s *Service) RecoveryActions() ([]RecoveryAction, error) { return nil, err } - var actions []windows.SC_ACTION - hdr := (*unsafeheader.Slice)(unsafe.Pointer(&actions)) - hdr.Data = unsafe.Pointer(p.Actions) - hdr.Len = int(p.ActionsCount) - hdr.Cap = int(p.ActionsCount) - + actions := unsafe.Slice(p.Actions, int(p.ActionsCount)) var recoveryActions []RecoveryAction for _, action := range actions { recoveryActions = append(recoveryActions, RecoveryAction{Type: int(action.Type), Delay: time.Duration(action.Delay) * time.Millisecond}) diff --git a/windows/svc/service.go b/windows/svc/service.go index 2b4a7bc6..e9e47f0b 100644 --- a/windows/svc/service.go +++ b/windows/svc/service.go @@ -13,7 +13,6 @@ import ( "sync" "unsafe" - "golang.org/x/sys/internal/unsafeheader" "golang.org/x/sys/windows" ) @@ -222,11 +221,7 @@ func serviceMain(argc uint32, argv **uint16) uintptr { defer func() { theService.h = 0 }() - var args16 []*uint16 - hdr := (*unsafeheader.Slice)(unsafe.Pointer(&args16)) - hdr.Data = unsafe.Pointer(argv) - hdr.Len = int(argc) - hdr.Cap = int(argc) + args16 := unsafe.Slice(argv, int(argc)) args := make([]string, len(args16)) for i, a := range args16 { diff --git a/windows/syscall_windows.go b/windows/syscall_windows.go index 67bad092..cb8c75a4 100644 --- a/windows/syscall_windows.go +++ b/windows/syscall_windows.go @@ -15,8 +15,6 @@ import ( "time" "unicode/utf16" "unsafe" - - "golang.org/x/sys/internal/unsafeheader" ) type Handle uintptr @@ -1667,12 +1665,8 @@ func NewNTUnicodeString(s string) (*NTUnicodeString, error) { // Slice returns a uint16 slice that aliases the data in the NTUnicodeString. func (s *NTUnicodeString) Slice() []uint16 { - var slice []uint16 - hdr := (*unsafeheader.Slice)(unsafe.Pointer(&slice)) - hdr.Data = unsafe.Pointer(s.Buffer) - hdr.Len = int(s.Length) - hdr.Cap = int(s.MaximumLength) - return slice + slice := unsafe.Slice(s.Buffer, s.MaximumLength) + return slice[:s.Length] } func (s *NTUnicodeString) String() string { @@ -1695,12 +1689,8 @@ func NewNTString(s string) (*NTString, error) { // Slice returns a byte slice that aliases the data in the NTString. func (s *NTString) Slice() []byte { - var slice []byte - hdr := (*unsafeheader.Slice)(unsafe.Pointer(&slice)) - hdr.Data = unsafe.Pointer(s.Buffer) - hdr.Len = int(s.Length) - hdr.Cap = int(s.MaximumLength) - return slice + slice := unsafe.Slice(s.Buffer, s.MaximumLength) + return slice[:s.Length] } func (s *NTString) String() string { @@ -1752,10 +1742,7 @@ func LoadResourceData(module, resInfo Handle) (data []byte, err error) { if err != nil { return } - h := (*unsafeheader.Slice)(unsafe.Pointer(&data)) - h.Data = unsafe.Pointer(ptr) - h.Len = int(size) - h.Cap = int(size) + data = unsafe.Slice((*byte)(unsafe.Pointer(ptr)), size) return } diff --git a/windows/syscall_windows_test.go b/windows/syscall_windows_test.go index 5b6bfb08..40b4d54e 100644 --- a/windows/syscall_windows_test.go +++ b/windows/syscall_windows_test.go @@ -22,7 +22,6 @@ import ( "time" "unsafe" - "golang.org/x/sys/internal/unsafeheader" "golang.org/x/sys/windows" ) @@ -865,10 +864,7 @@ func TestSystemModuleVersions(t *testing.T) { return } mods := (*windows.RTL_PROCESS_MODULES)(unsafe.Pointer(&moduleBuffer[0])) - hdr := (*unsafeheader.Slice)(unsafe.Pointer(&modules)) - hdr.Data = unsafe.Pointer(&mods.Modules[0]) - hdr.Len = int(mods.NumberOfModules) - hdr.Cap = int(mods.NumberOfModules) + modules = unsafe.Slice(&mods.Modules[0], int(mods.NumberOfModules)) break } for i := range modules {