]> Cypherpunks repositories - gostls13.git/commitdiff
internal/unsafeheader: consolidate stringHeader and sliceHeader declarations into...
authorBryan C. Mills <bcmills@google.com>
Thu, 30 Apr 2020 21:05:59 +0000 (17:05 -0400)
committerBryan C. Mills <bcmills@google.com>
Fri, 1 May 2020 02:31:29 +0000 (02:31 +0000)
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 #37805
Updates #19367

Change-Id: I7a6d93ef8dd6e235bcab94e7c47270aad047af31
Reviewed-on: https://go-review.googlesource.com/c/go/+/231223
Reviewed-by: Ian Lance Taylor <iant@golang.org>
13 files changed:
src/cmd/dist/buildtool.go
src/cmd/internal/goobj2/objfile.go
src/cmd/oldlink/internal/objfile/objfile.go
src/go/build/deps_test.go
src/internal/reflectlite/swapper.go
src/internal/reflectlite/type.go
src/internal/reflectlite/value.go
src/internal/unsafeheader/unsafeheader.go [new file with mode: 0644]
src/internal/unsafeheader/unsafeheader_test.go [new file with mode: 0644]
src/reflect/swapper.go
src/reflect/type.go
src/reflect/value.go
src/syscall/syscall_unix.go

index 5ec2381589c6139ee1320054966d7bb595004717..9059225abdd0920bc8decd65b176b88afdfe7070 100644 (file)
@@ -97,6 +97,7 @@ var bootstrapDirs = []string{
        "debug/pe",
        "internal/goversion",
        "internal/race",
+       "internal/unsafeheader",
        "internal/xcoff",
        "math/big",
        "math/bits",
index 28702ebf0738c1d297d622288252226a0d609e2a..ab0762456337d98d3a2478f0ee8accf5dd981922 100644 (file)
@@ -12,6 +12,7 @@ import (
        "encoding/binary"
        "errors"
        "fmt"
+       "internal/unsafeheader"
        "io"
        "unsafe"
 )
@@ -502,16 +503,15 @@ func (r *Reader) StringAt(off uint32, len uint32) string {
 }
 
 func toString(b []byte) string {
-       type stringHeader struct {
-               str unsafe.Pointer
-               len int
-       }
-
        if len(b) == 0 {
                return ""
        }
-       ss := stringHeader{str: unsafe.Pointer(&b[0]), len: len(b)}
-       s := *(*string)(unsafe.Pointer(&ss))
+
+       var s string
+       hdr := (*unsafeheader.String)(unsafe.Pointer(&s))
+       hdr.Data = unsafe.Pointer(&b[0])
+       hdr.Len = len(b)
+
        return s
 }
 
index 3a59f6a6249c2d8df3b85cfa135deb1802ee3298..6882b7694b19669d6303d28fb8df04bef25e82b6 100644 (file)
@@ -19,6 +19,7 @@ import (
        "cmd/internal/sys"
        "cmd/oldlink/internal/sym"
        "fmt"
+       "internal/unsafeheader"
        "io"
        "log"
        "os"
@@ -595,17 +596,16 @@ func (r *objReader) readData() []byte {
        return p
 }
 
-type stringHeader struct {
-       str unsafe.Pointer
-       len int
-}
-
 func mkROString(rodata []byte) string {
        if len(rodata) == 0 {
                return ""
        }
-       ss := stringHeader{str: unsafe.Pointer(&rodata[0]), len: len(rodata)}
-       s := *(*string)(unsafe.Pointer(&ss))
+
+       var s string
+       hdr := (*unsafeheader.String)(unsafe.Pointer(&s))
+       hdr.Data = unsafe.Pointer(&rodata[0])
+       hdr.Len = len(rodata)
+
        return s
 }
 
index 45c92c8eb41f3fbb2a1bf0d117cfe0a1dccc11f2..a5b45fada153cf16fc5b0e7a8bc934bb5d860031 100644 (file)
@@ -46,7 +46,8 @@ var pkgDeps = map[string][]string{
        "unsafe":                  {},
        "internal/cpu":            {},
        "internal/bytealg":        {"unsafe", "internal/cpu"},
-       "internal/reflectlite":    {"runtime", "unsafe"},
+       "internal/reflectlite":    {"runtime", "unsafe", "internal/unsafeheader"},
+       "internal/unsafeheader":   {"unsafe"},
 
        "L0": {
                "errors",
@@ -119,7 +120,7 @@ var pkgDeps = map[string][]string{
        "image/color":            {"L2"},                // interfaces
        "image/color/palette":    {"L2", "image/color"},
        "internal/fmtsort":       {"reflect", "sort"},
-       "reflect":                {"L2"},
+       "reflect":                {"L2", "internal/unsafeheader"},
        "sort":                   {"internal/reflectlite"},
 
        "L3": {
@@ -147,7 +148,7 @@ var pkgDeps = map[string][]string{
        // End of linear dependency definitions.
 
        // Operating system access.
-       "syscall":                           {"L0", "internal/oserror", "internal/race", "internal/syscall/windows/sysdll", "syscall/js", "unicode/utf16"},
+       "syscall":                           {"L0", "internal/oserror", "internal/race", "internal/syscall/windows/sysdll", "internal/unsafeheader", "syscall/js", "unicode/utf16"},
        "syscall/js":                        {"L0"},
        "internal/oserror":                  {"L0"},
        "internal/syscall/unix":             {"L0", "syscall"},
index 4594fb5ee25909cb11d33ba6b62ef93329079e09..6330ab2d34668dd8f85719120befb61cd75c1984 100644 (file)
@@ -4,7 +4,10 @@
 
 package reflectlite
 
-import "unsafe"
+import (
+       "internal/unsafeheader"
+       "unsafe"
+)
 
 // Swapper returns a function that swaps the elements in the provided
 // slice.
@@ -58,7 +61,7 @@ func Swapper(slice interface{}) func(i, j int) {
                }
        }
 
-       s := (*sliceHeader)(v.ptr)
+       s := (*unsafeheader.Slice)(v.ptr)
        tmp := unsafe_New(typ) // swap scratch space
 
        return func(i, j int) {
index 49a03ac1e1bedc52f3b2d701509d99be892e8ef9..eb7f1a4b78e7193903a34ef3ac08c9c3a1232799 100644 (file)
@@ -7,6 +7,7 @@
 package reflectlite
 
 import (
+       "internal/unsafeheader"
        "unsafe"
 )
 
@@ -338,7 +339,7 @@ func (n name) name() (s string) {
        }
        b := (*[4]byte)(unsafe.Pointer(n.bytes))
 
-       hdr := (*stringHeader)(unsafe.Pointer(&s))
+       hdr := (*unsafeheader.String)(unsafe.Pointer(&s))
        hdr.Data = unsafe.Pointer(&b[3])
        hdr.Len = int(b[1])<<8 | int(b[2])
        return s
@@ -350,7 +351,7 @@ func (n name) tag() (s string) {
                return ""
        }
        nl := n.nameLen()
-       hdr := (*stringHeader)(unsafe.Pointer(&s))
+       hdr := (*unsafeheader.String)(unsafe.Pointer(&s))
        hdr.Data = unsafe.Pointer(n.data(3+nl+2, "non-empty string"))
        hdr.Len = tl
        return s
index 6a493938f536ad43176995e3d4a8089ea91a879e..85beea606c80043f4ec1686cfcbf717f1b9f5745 100644 (file)
@@ -5,6 +5,7 @@
 package reflectlite
 
 import (
+       "internal/unsafeheader"
        "runtime"
        "unsafe"
 )
@@ -335,10 +336,10 @@ func (v Value) Len() int {
                return maplen(v.pointer())
        case Slice:
                // Slice is bigger than a word; assume flagIndir.
-               return (*sliceHeader)(v.ptr).Len
+               return (*unsafeheader.Slice)(v.ptr).Len
        case String:
                // String is bigger than a word; assume flagIndir.
-               return (*stringHeader)(v.ptr).Len
+               return (*unsafeheader.String)(v.ptr).Len
        }
        panic(&ValueError{"reflect.Value.Len", v.kind()})
 }
@@ -379,19 +380,6 @@ func (v Value) Type() Type {
        return v.typ
 }
 
-// stringHeader is a safe version of StringHeader used within this package.
-type stringHeader struct {
-       Data unsafe.Pointer
-       Len  int
-}
-
-// sliceHeader is a safe version of SliceHeader used within this package.
-type sliceHeader struct {
-       Data unsafe.Pointer
-       Len  int
-       Cap  int
-}
-
 /*
  * constructors
  */
diff --git a/src/internal/unsafeheader/unsafeheader.go b/src/internal/unsafeheader/unsafeheader.go
new file mode 100644 (file)
index 0000000..2d4d00d
--- /dev/null
@@ -0,0 +1,37 @@
+// 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 packages that cannot import "reflect" to use types that
+// are tested to be equivalent to reflect.SliceHeader and reflect.StringHeader.
+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.
+//
+// Unlike reflect.SliceHeader, its Data field is sufficient to guarantee the
+// data it references will not be garbage collected.
+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.
+//
+// Unlike reflect.SliceHeader, its Data field is sufficient to guarantee the
+// data it references will not be garbage collected.
+type String struct {
+       Data unsafe.Pointer
+       Len  int
+}
diff --git a/src/internal/unsafeheader/unsafeheader_test.go b/src/internal/unsafeheader/unsafeheader_test.go
new file mode 100644 (file)
index 0000000..6fb7cca
--- /dev/null
@@ -0,0 +1,100 @@
+// 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"
+       "internal/unsafeheader"
+       "reflect"
+       "testing"
+       "unsafe"
+)
+
+// 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)
+               }
+       })
+}
index 016f95d7b01afd7353c62b7423090d095e7ab793..0cf40666b1e8e5c35a0920440b75f579e72c0a2e 100644 (file)
@@ -4,7 +4,10 @@
 
 package reflect
 
-import "unsafe"
+import (
+       "internal/unsafeheader"
+       "unsafe"
+)
 
 // Swapper returns a function that swaps the elements in the provided
 // slice.
@@ -58,7 +61,7 @@ func Swapper(slice interface{}) func(i, j int) {
                }
        }
 
-       s := (*sliceHeader)(v.ptr)
+       s := (*unsafeheader.Slice)(v.ptr)
        tmp := unsafe_New(typ) // swap scratch space
 
        return func(i, j int) {
index e88a2f602661f35d16a86c48fef42986bba96b5b..ec26bef091e17afe38c452a1dd3341a52ecbaba1 100644 (file)
@@ -16,6 +16,7 @@
 package reflect
 
 import (
+       "internal/unsafeheader"
        "strconv"
        "sync"
        "unicode"
@@ -490,7 +491,7 @@ func (n name) name() (s string) {
        }
        b := (*[4]byte)(unsafe.Pointer(n.bytes))
 
-       hdr := (*stringHeader)(unsafe.Pointer(&s))
+       hdr := (*unsafeheader.String)(unsafe.Pointer(&s))
        hdr.Data = unsafe.Pointer(&b[3])
        hdr.Len = int(b[1])<<8 | int(b[2])
        return s
@@ -502,7 +503,7 @@ func (n name) tag() (s string) {
                return ""
        }
        nl := n.nameLen()
-       hdr := (*stringHeader)(unsafe.Pointer(&s))
+       hdr := (*unsafeheader.String)(unsafe.Pointer(&s))
        hdr.Data = unsafe.Pointer(n.data(3+nl+2, "non-empty string"))
        hdr.Len = tl
        return s
index b0f06b936e77c94b22eefc9efa857be0960891a9..abddd1774f753cd81d7137b3378f1c801a66f62f 100644 (file)
@@ -5,6 +5,7 @@
 package reflect
 
 import (
+       "internal/unsafeheader"
        "math"
        "runtime"
        "unsafe"
@@ -766,7 +767,7 @@ func (v Value) Cap() int {
                return chancap(v.pointer())
        case Slice:
                // Slice is always bigger than a word; assume flagIndir.
-               return (*sliceHeader)(v.ptr).Cap
+               return (*unsafeheader.Slice)(v.ptr).Cap
        }
        panic(&ValueError{"reflect.Value.Cap", v.kind()})
 }
@@ -945,7 +946,7 @@ func (v Value) Index(i int) Value {
        case Slice:
                // Element flag same as Elem of Ptr.
                // Addressable, indirect, possibly read-only.
-               s := (*sliceHeader)(v.ptr)
+               s := (*unsafeheader.Slice)(v.ptr)
                if uint(i) >= uint(s.Len) {
                        panic("reflect: slice index out of range")
                }
@@ -956,7 +957,7 @@ func (v Value) Index(i int) Value {
                return Value{typ, val, fl}
 
        case String:
-               s := (*stringHeader)(v.ptr)
+               s := (*unsafeheader.String)(v.ptr)
                if uint(i) >= uint(s.Len) {
                        panic("reflect: string index out of range")
                }
@@ -1143,10 +1144,10 @@ func (v Value) Len() int {
                return maplen(v.pointer())
        case Slice:
                // Slice is bigger than a word; assume flagIndir.
-               return (*sliceHeader)(v.ptr).Len
+               return (*unsafeheader.Slice)(v.ptr).Len
        case String:
                // String is bigger than a word; assume flagIndir.
-               return (*stringHeader)(v.ptr).Len
+               return (*unsafeheader.String)(v.ptr).Len
        }
        panic(&ValueError{"reflect.Value.Len", v.kind()})
 }
@@ -1632,7 +1633,7 @@ func (v Value) SetInt(x int64) {
 func (v Value) SetLen(n int) {
        v.mustBeAssignable()
        v.mustBe(Slice)
-       s := (*sliceHeader)(v.ptr)
+       s := (*unsafeheader.Slice)(v.ptr)
        if uint(n) > uint(s.Cap) {
                panic("reflect: slice length out of range in SetLen")
        }
@@ -1645,7 +1646,7 @@ func (v Value) SetLen(n int) {
 func (v Value) SetCap(n int) {
        v.mustBeAssignable()
        v.mustBe(Slice)
-       s := (*sliceHeader)(v.ptr)
+       s := (*unsafeheader.Slice)(v.ptr)
        if n < s.Len || n > s.Cap {
                panic("reflect: slice capacity out of range in SetCap")
        }
@@ -1747,18 +1748,18 @@ func (v Value) Slice(i, j int) Value {
 
        case Slice:
                typ = (*sliceType)(unsafe.Pointer(v.typ))
-               s := (*sliceHeader)(v.ptr)
+               s := (*unsafeheader.Slice)(v.ptr)
                base = s.Data
                cap = s.Cap
 
        case String:
-               s := (*stringHeader)(v.ptr)
+               s := (*unsafeheader.String)(v.ptr)
                if i < 0 || j < i || j > s.Len {
                        panic("reflect.Value.Slice: string slice index out of bounds")
                }
-               var t stringHeader
+               var t unsafeheader.String
                if i < s.Len {
-                       t = stringHeader{arrayAt(s.Data, i, 1, "i < s.Len"), j - i}
+                       t = unsafeheader.String{Data: arrayAt(s.Data, i, 1, "i < s.Len"), Len: j - i}
                }
                return Value{v.typ, unsafe.Pointer(&t), v.flag}
        }
@@ -1770,8 +1771,8 @@ func (v Value) Slice(i, j int) Value {
        // Declare slice so that gc can see the base pointer in it.
        var x []unsafe.Pointer
 
-       // Reinterpret as *sliceHeader to edit.
-       s := (*sliceHeader)(unsafe.Pointer(&x))
+       // Reinterpret as *unsafeheader.Slice to edit.
+       s := (*unsafeheader.Slice)(unsafe.Pointer(&x))
        s.Len = j - i
        s.Cap = cap - i
        if cap-i > 0 {
@@ -1809,7 +1810,7 @@ func (v Value) Slice3(i, j, k int) Value {
 
        case Slice:
                typ = (*sliceType)(unsafe.Pointer(v.typ))
-               s := (*sliceHeader)(v.ptr)
+               s := (*unsafeheader.Slice)(v.ptr)
                base = s.Data
                cap = s.Cap
        }
@@ -1822,8 +1823,8 @@ func (v Value) Slice3(i, j, k int) Value {
        // can see the base pointer in it.
        var x []unsafe.Pointer
 
-       // Reinterpret as *sliceHeader to edit.
-       s := (*sliceHeader)(unsafe.Pointer(&x))
+       // Reinterpret as *unsafeheader.Slice to edit.
+       s := (*unsafeheader.Slice)(unsafe.Pointer(&x))
        s.Len = j - i
        s.Cap = k - i
        if k-i > 0 {
@@ -1960,12 +1961,6 @@ type StringHeader struct {
        Len  int
 }
 
-// stringHeader is a safe version of StringHeader used within this package.
-type stringHeader struct {
-       Data unsafe.Pointer
-       Len  int
-}
-
 // SliceHeader is the runtime representation of a slice.
 // It cannot be used safely or portably and its representation may
 // change in a later release.
@@ -1978,13 +1973,6 @@ type SliceHeader struct {
        Cap  int
 }
 
-// sliceHeader is a safe version of SliceHeader used within this package.
-type sliceHeader struct {
-       Data unsafe.Pointer
-       Len  int
-       Cap  int
-}
-
 func typesMustMatch(what string, t1, t2 Type) {
        if t1 != t2 {
                panic(what + ": " + t1.String() + " != " + t2.String())
@@ -2085,22 +2073,22 @@ func Copy(dst, src Value) int {
                typesMustMatch("reflect.Copy", de, se)
        }
 
-       var ds, ss sliceHeader
+       var ds, ss unsafeheader.Slice
        if dk == Array {
                ds.Data = dst.ptr
                ds.Len = dst.Len()
                ds.Cap = ds.Len
        } else {
-               ds = *(*sliceHeader)(dst.ptr)
+               ds = *(*unsafeheader.Slice)(dst.ptr)
        }
        if sk == Array {
                ss.Data = src.ptr
                ss.Len = src.Len()
                ss.Cap = ss.Len
        } else if sk == Slice {
-               ss = *(*sliceHeader)(src.ptr)
+               ss = *(*unsafeheader.Slice)(src.ptr)
        } else {
-               sh := *(*stringHeader)(src.ptr)
+               sh := *(*unsafeheader.String)(src.ptr)
                ss.Data = sh.Data
                ss.Len = sh.Len
                ss.Cap = sh.Len
@@ -2288,7 +2276,7 @@ func MakeSlice(typ Type, len, cap int) Value {
                panic("reflect.MakeSlice: len > cap")
        }
 
-       s := sliceHeader{unsafe_NewArray(typ.Elem().(*rtype), cap), len, cap}
+       s := unsafeheader.Slice{Data: unsafe_NewArray(typ.Elem().(*rtype), cap), Len: len, Cap: cap}
        return Value{typ.(*rtype), unsafe.Pointer(&s), flagIndir | flag(Slice)}
 }
 
@@ -2805,7 +2793,7 @@ func typedmemclrpartial(t *rtype, ptr unsafe.Pointer, off, size uintptr)
 // typedslicecopy copies a slice of elemType values from src to dst,
 // returning the number of elements copied.
 //go:noescape
-func typedslicecopy(elemType *rtype, dst, src sliceHeader) int
+func typedslicecopy(elemType *rtype, dst, src unsafeheader.Slice) int
 
 //go:noescape
 func typehash(t *rtype, p unsafe.Pointer, h uintptr) uintptr
index b8b8a7c111b365a7db5cc9f7e7abef8917caa94d..56abce19cd2cbccc7974b833fbc3d1b07fc126a3 100644 (file)
@@ -9,6 +9,7 @@ package syscall
 import (
        "internal/oserror"
        "internal/race"
+       "internal/unsafeheader"
        "runtime"
        "sync"
        "unsafe"
@@ -60,15 +61,12 @@ func (m *mmapper) Mmap(fd int, offset int64, length int, prot int, flags int) (d
                return nil, errno
        }
 
-       // Slice memory layout
-       var sl = struct {
-               addr uintptr
-               len  int
-               cap  int
-       }{addr, length, length}
-
-       // Use unsafe to turn sl into a []byte.
-       b := *(*[]byte)(unsafe.Pointer(&sl))
+       // Use unsafe to turn addr into a []byte.
+       var b []byte
+       hdr := (*unsafeheader.Slice)(unsafe.Pointer(&b))
+       hdr.Data = unsafe.Pointer(addr)
+       hdr.Cap = length
+       hdr.Len = length
 
        // Register mapping in m and return it.
        p := &b[cap(b)-1]