]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: add support for unsafe.{String,StringData,SliceData}
authorcuiweixie <cuiweixie@gmail.com>
Tue, 16 Aug 2022 09:52:13 +0000 (17:52 +0800)
committerMatthew Dempsky <mdempsky@google.com>
Wed, 31 Aug 2022 17:15:15 +0000 (17:15 +0000)
For #53003

Change-Id: I13a761daca8b433b271a1feb711c103d9820772d
Reviewed-on: https://go-review.googlesource.com/c/go/+/423774
Reviewed-by: Heschi Kreinick <heschi@google.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: hopehook <hopehook@golangcn.org>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Keith Randall <khr@golang.org>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>

29 files changed:
src/cmd/compile/internal/escape/call.go
src/cmd/compile/internal/escape/expr.go
src/cmd/compile/internal/ir/expr.go
src/cmd/compile/internal/ir/fmt.go
src/cmd/compile/internal/ir/node.go
src/cmd/compile/internal/ir/node_gen.go
src/cmd/compile/internal/ir/op_string.go
src/cmd/compile/internal/noder/transform.go
src/cmd/compile/internal/ssagen/ssa.go
src/cmd/compile/internal/typecheck/builtin.go
src/cmd/compile/internal/typecheck/builtin/runtime.go
src/cmd/compile/internal/typecheck/const.go
src/cmd/compile/internal/typecheck/expr.go
src/cmd/compile/internal/typecheck/func.go
src/cmd/compile/internal/typecheck/iexport.go
src/cmd/compile/internal/typecheck/iimport.go
src/cmd/compile/internal/typecheck/typecheck.go
src/cmd/compile/internal/typecheck/universe.go
src/cmd/compile/internal/walk/builtin.go
src/cmd/compile/internal/walk/expr.go
src/cmd/compile/internal/walk/walk.go
src/runtime/checkptr_test.go
src/runtime/slice.go
src/runtime/testdata/testprog/checkptr.go
src/runtime/unsafe.go [new file with mode: 0644]
test/unsafe_slice_data.go [new file with mode: 0644]
test/unsafe_string.go [new file with mode: 0644]
test/unsafe_string_data.go [new file with mode: 0644]
test/unsafebuiltins.go

index ee76adb0fac17ddfa4e68cb7912e0553d0fe2185..880d789aa11e49fef92b77ab9372a1367095debe 100644 (file)
@@ -180,11 +180,11 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir
                        argument(e.discardHole(), &call.Args[i])
                }
 
-       case ir.OLEN, ir.OCAP, ir.OREAL, ir.OIMAG, ir.OCLOSE:
+       case ir.OLEN, ir.OCAP, ir.OREAL, ir.OIMAG, ir.OCLOSE, ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
                call := call.(*ir.UnaryExpr)
                argument(e.discardHole(), &call.X)
 
-       case ir.OUNSAFEADD, ir.OUNSAFESLICE:
+       case ir.OUNSAFEADD, ir.OUNSAFESLICE, ir.OUNSAFESTRING:
                call := call.(*ir.BinaryExpr)
                argument(ks[0], &call.X)
                argument(e.discardHole(), &call.Y)
index f9d83b3f3591ccfe86e8db58e23f89464f4126db..fd758bbf2081837cb4ef86a6875244f864f38c24 100644 (file)
@@ -134,7 +134,9 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) {
                n := n.(*ir.UnaryExpr)
                e.discard(n.X)
 
-       case ir.OCALLMETH, ir.OCALLFUNC, ir.OCALLINTER, ir.OINLCALL, ir.OLEN, ir.OCAP, ir.OCOMPLEX, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCOPY, ir.ORECOVER, ir.OUNSAFEADD, ir.OUNSAFESLICE:
+       case ir.OCALLMETH, ir.OCALLFUNC, ir.OCALLINTER, ir.OINLCALL,
+               ir.OLEN, ir.OCAP, ir.OCOMPLEX, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCOPY, ir.ORECOVER,
+               ir.OUNSAFEADD, ir.OUNSAFESLICE, ir.OUNSAFESTRING, ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
                e.call([]hole{k}, n)
 
        case ir.ONEW:
index 5171f8643482d3e3514e290c4861dfedb51e99a2..ff315bd02752226b6556a28b8ce4c0ca36359902 100644 (file)
@@ -137,7 +137,7 @@ func (n *BinaryExpr) SetOp(op Op) {
                panic(n.no("SetOp " + op.String()))
        case OADD, OADDSTR, OAND, OANDNOT, ODIV, OEQ, OGE, OGT, OLE,
                OLSH, OLT, OMOD, OMUL, ONE, OOR, ORSH, OSUB, OXOR,
-               OCOPY, OCOMPLEX, OUNSAFEADD, OUNSAFESLICE,
+               OCOPY, OCOMPLEX, OUNSAFEADD, OUNSAFESLICE, OUNSAFESTRING,
                OEFACE:
                n.op = op
        }
@@ -624,6 +624,21 @@ func NewSliceHeaderExpr(pos src.XPos, typ *types.Type, ptr, len, cap Node) *Slic
        return n
 }
 
+// A StringHeaderExpr expression constructs a string header from its parts.
+type StringHeaderExpr struct {
+       miniExpr
+       Ptr Node
+       Len Node
+}
+
+func NewStringHeaderExpr(pos src.XPos, ptr, len Node) *StringHeaderExpr {
+       n := &StringHeaderExpr{Ptr: ptr, Len: len}
+       n.pos = pos
+       n.op = OSTRINGHEADER
+       n.typ = types.Types[types.TSTRING]
+       return n
+}
+
 // A StarExpr is a dereference expression *X.
 // It may end up being a value or a type.
 type StarExpr struct {
@@ -734,7 +749,8 @@ func (n *UnaryExpr) SetOp(op Op) {
        case OBITNOT, ONEG, ONOT, OPLUS, ORECV,
                OALIGNOF, OCAP, OCLOSE, OIMAG, OLEN, ONEW,
                OOFFSETOF, OPANIC, OREAL, OSIZEOF,
-               OCHECKNIL, OCFUNC, OIDATA, OITAB, OSPTR:
+               OCHECKNIL, OCFUNC, OIDATA, OITAB, OSPTR,
+               OUNSAFESTRINGDATA, OUNSAFESLICEDATA:
                n.op = op
        }
 }
index f12054e657b117d797057729a24258870ca43682..d051c88a29e95806cd9313b4ef7c9c6851734d6d 100644 (file)
@@ -25,70 +25,73 @@ import (
 // Op
 
 var OpNames = []string{
-       OADDR:        "&",
-       OADD:         "+",
-       OADDSTR:      "+",
-       OALIGNOF:     "unsafe.Alignof",
-       OANDAND:      "&&",
-       OANDNOT:      "&^",
-       OAND:         "&",
-       OAPPEND:      "append",
-       OAS:          "=",
-       OAS2:         "=",
-       OBREAK:       "break",
-       OCALL:        "function call", // not actual syntax
-       OCAP:         "cap",
-       OCASE:        "case",
-       OCLOSE:       "close",
-       OCOMPLEX:     "complex",
-       OBITNOT:      "^",
-       OCONTINUE:    "continue",
-       OCOPY:        "copy",
-       ODELETE:      "delete",
-       ODEFER:       "defer",
-       ODIV:         "/",
-       OEQ:          "==",
-       OFALL:        "fallthrough",
-       OFOR:         "for",
-       OGE:          ">=",
-       OGOTO:        "goto",
-       OGT:          ">",
-       OIF:          "if",
-       OIMAG:        "imag",
-       OINLMARK:     "inlmark",
-       ODEREF:       "*",
-       OLEN:         "len",
-       OLE:          "<=",
-       OLSH:         "<<",
-       OLT:          "<",
-       OMAKE:        "make",
-       ONEG:         "-",
-       OMOD:         "%",
-       OMUL:         "*",
-       ONEW:         "new",
-       ONE:          "!=",
-       ONOT:         "!",
-       OOFFSETOF:    "unsafe.Offsetof",
-       OOROR:        "||",
-       OOR:          "|",
-       OPANIC:       "panic",
-       OPLUS:        "+",
-       OPRINTN:      "println",
-       OPRINT:       "print",
-       ORANGE:       "range",
-       OREAL:        "real",
-       ORECV:        "<-",
-       ORECOVER:     "recover",
-       ORETURN:      "return",
-       ORSH:         ">>",
-       OSELECT:      "select",
-       OSEND:        "<-",
-       OSIZEOF:      "unsafe.Sizeof",
-       OSUB:         "-",
-       OSWITCH:      "switch",
-       OUNSAFEADD:   "unsafe.Add",
-       OUNSAFESLICE: "unsafe.Slice",
-       OXOR:         "^",
+       OADDR:             "&",
+       OADD:              "+",
+       OADDSTR:           "+",
+       OALIGNOF:          "unsafe.Alignof",
+       OANDAND:           "&&",
+       OANDNOT:           "&^",
+       OAND:              "&",
+       OAPPEND:           "append",
+       OAS:               "=",
+       OAS2:              "=",
+       OBREAK:            "break",
+       OCALL:             "function call", // not actual syntax
+       OCAP:              "cap",
+       OCASE:             "case",
+       OCLOSE:            "close",
+       OCOMPLEX:          "complex",
+       OBITNOT:           "^",
+       OCONTINUE:         "continue",
+       OCOPY:             "copy",
+       ODELETE:           "delete",
+       ODEFER:            "defer",
+       ODIV:              "/",
+       OEQ:               "==",
+       OFALL:             "fallthrough",
+       OFOR:              "for",
+       OGE:               ">=",
+       OGOTO:             "goto",
+       OGT:               ">",
+       OIF:               "if",
+       OIMAG:             "imag",
+       OINLMARK:          "inlmark",
+       ODEREF:            "*",
+       OLEN:              "len",
+       OLE:               "<=",
+       OLSH:              "<<",
+       OLT:               "<",
+       OMAKE:             "make",
+       ONEG:              "-",
+       OMOD:              "%",
+       OMUL:              "*",
+       ONEW:              "new",
+       ONE:               "!=",
+       ONOT:              "!",
+       OOFFSETOF:         "unsafe.Offsetof",
+       OOROR:             "||",
+       OOR:               "|",
+       OPANIC:            "panic",
+       OPLUS:             "+",
+       OPRINTN:           "println",
+       OPRINT:            "print",
+       ORANGE:            "range",
+       OREAL:             "real",
+       ORECV:             "<-",
+       ORECOVER:          "recover",
+       ORETURN:           "return",
+       ORSH:              ">>",
+       OSELECT:           "select",
+       OSEND:             "<-",
+       OSIZEOF:           "unsafe.Sizeof",
+       OSUB:              "-",
+       OSWITCH:           "switch",
+       OUNSAFEADD:        "unsafe.Add",
+       OUNSAFESLICE:      "unsafe.Slice",
+       OUNSAFESLICEDATA:  "unsafe.SliceData",
+       OUNSAFESTRING:     "unsafe.String",
+       OUNSAFESTRINGDATA: "unsafe.StringData",
+       OXOR:              "^",
 }
 
 // GoString returns the Go syntax for the Op, or else its name.
@@ -168,94 +171,98 @@ func fmtNode(n Node, s fmt.State, verb rune) {
 }
 
 var OpPrec = []int{
-       OALIGNOF:       8,
-       OAPPEND:        8,
-       OBYTES2STR:     8,
-       OARRAYLIT:      8,
-       OSLICELIT:      8,
-       ORUNES2STR:     8,
-       OCALLFUNC:      8,
-       OCALLINTER:     8,
-       OCALLMETH:      8,
-       OCALL:          8,
-       OCAP:           8,
-       OCLOSE:         8,
-       OCOMPLIT:       8,
-       OCONVIFACE:     8,
-       OCONVIDATA:     8,
-       OCONVNOP:       8,
-       OCONV:          8,
-       OCOPY:          8,
-       ODELETE:        8,
-       OGETG:          8,
-       OLEN:           8,
-       OLITERAL:       8,
-       OMAKESLICE:     8,
-       OMAKESLICECOPY: 8,
-       OMAKE:          8,
-       OMAPLIT:        8,
-       ONAME:          8,
-       ONEW:           8,
-       ONIL:           8,
-       ONONAME:        8,
-       OOFFSETOF:      8,
-       OPANIC:         8,
-       OPAREN:         8,
-       OPRINTN:        8,
-       OPRINT:         8,
-       ORUNESTR:       8,
-       OSIZEOF:        8,
-       OSLICE2ARRPTR:  8,
-       OSTR2BYTES:     8,
-       OSTR2RUNES:     8,
-       OSTRUCTLIT:     8,
-       OTYPE:          8,
-       OUNSAFEADD:     8,
-       OUNSAFESLICE:   8,
-       OINDEXMAP:      8,
-       OINDEX:         8,
-       OSLICE:         8,
-       OSLICESTR:      8,
-       OSLICEARR:      8,
-       OSLICE3:        8,
-       OSLICE3ARR:     8,
-       OSLICEHEADER:   8,
-       ODOTINTER:      8,
-       ODOTMETH:       8,
-       ODOTPTR:        8,
-       ODOTTYPE2:      8,
-       ODOTTYPE:       8,
-       ODOT:           8,
-       OXDOT:          8,
-       OMETHVALUE:     8,
-       OMETHEXPR:      8,
-       OPLUS:          7,
-       ONOT:           7,
-       OBITNOT:        7,
-       ONEG:           7,
-       OADDR:          7,
-       ODEREF:         7,
-       ORECV:          7,
-       OMUL:           6,
-       ODIV:           6,
-       OMOD:           6,
-       OLSH:           6,
-       ORSH:           6,
-       OAND:           6,
-       OANDNOT:        6,
-       OADD:           5,
-       OSUB:           5,
-       OOR:            5,
-       OXOR:           5,
-       OEQ:            4,
-       OLT:            4,
-       OLE:            4,
-       OGE:            4,
-       OGT:            4,
-       ONE:            4,
-       OSEND:          3,
-       OANDAND:        2,
-       OOROR:          1,
+       OALIGNOF:          8,
+       OAPPEND:           8,
+       OBYTES2STR:        8,
+       OARRAYLIT:         8,
+       OSLICELIT:         8,
+       ORUNES2STR:        8,
+       OCALLFUNC:         8,
+       OCALLINTER:        8,
+       OCALLMETH:         8,
+       OCALL:             8,
+       OCAP:              8,
+       OCLOSE:            8,
+       OCOMPLIT:          8,
+       OCONVIFACE:        8,
+       OCONVIDATA:        8,
+       OCONVNOP:          8,
+       OCONV:             8,
+       OCOPY:             8,
+       ODELETE:           8,
+       OGETG:             8,
+       OLEN:              8,
+       OLITERAL:          8,
+       OMAKESLICE:        8,
+       OMAKESLICECOPY:    8,
+       OMAKE:             8,
+       OMAPLIT:           8,
+       ONAME:             8,
+       ONEW:              8,
+       ONIL:              8,
+       ONONAME:           8,
+       OOFFSETOF:         8,
+       OPANIC:            8,
+       OPAREN:            8,
+       OPRINTN:           8,
+       OPRINT:            8,
+       ORUNESTR:          8,
+       OSIZEOF:           8,
+       OSLICE2ARRPTR:     8,
+       OSTR2BYTES:        8,
+       OSTR2RUNES:        8,
+       OSTRUCTLIT:        8,
+       OTYPE:             8,
+       OUNSAFEADD:        8,
+       OUNSAFESLICE:      8,
+       OUNSAFESLICEDATA:  8,
+       OUNSAFESTRING:     8,
+       OUNSAFESTRINGDATA: 8,
+       OINDEXMAP:         8,
+       OINDEX:            8,
+       OSLICE:            8,
+       OSLICESTR:         8,
+       OSLICEARR:         8,
+       OSLICE3:           8,
+       OSLICE3ARR:        8,
+       OSLICEHEADER:      8,
+       OSTRINGHEADER:     8,
+       ODOTINTER:         8,
+       ODOTMETH:          8,
+       ODOTPTR:           8,
+       ODOTTYPE2:         8,
+       ODOTTYPE:          8,
+       ODOT:              8,
+       OXDOT:             8,
+       OMETHVALUE:        8,
+       OMETHEXPR:         8,
+       OPLUS:             7,
+       ONOT:              7,
+       OBITNOT:           7,
+       ONEG:              7,
+       OADDR:             7,
+       ODEREF:            7,
+       ORECV:             7,
+       OMUL:              6,
+       ODIV:              6,
+       OMOD:              6,
+       OLSH:              6,
+       ORSH:              6,
+       OAND:              6,
+       OANDNOT:           6,
+       OADD:              5,
+       OSUB:              5,
+       OOR:               5,
+       OXOR:              5,
+       OEQ:               4,
+       OLT:               4,
+       OLE:               4,
+       OGE:               4,
+       OGT:               4,
+       ONE:               4,
+       OSEND:             3,
+       OANDAND:           2,
+       OOROR:             1,
 
        // Statements handled by stmtfmt
        OAS:         -1,
index 9d1c8cbb9be2452bd47d20a7b29886140c6942b0..4196622b8a3587a60d95a0b85593880ba3a04993 100644 (file)
@@ -209,45 +209,49 @@ const (
        //
        // This node is created so the walk pass can optimize this pattern which would
        // otherwise be hard to detect after the order pass.
-       OMUL         // X * Y
-       ODIV         // X / Y
-       OMOD         // X % Y
-       OLSH         // X << Y
-       ORSH         // X >> Y
-       OAND         // X & Y
-       OANDNOT      // X &^ Y
-       ONEW         // new(X); corresponds to calls to new in source code
-       ONOT         // !X
-       OBITNOT      // ^X
-       OPLUS        // +X
-       ONEG         // -X
-       OOROR        // X || Y
-       OPANIC       // panic(X)
-       OPRINT       // print(List)
-       OPRINTN      // println(List)
-       OPAREN       // (X)
-       OSEND        // Chan <- Value
-       OSLICE       // X[Low : High] (X is untypechecked or slice)
-       OSLICEARR    // X[Low : High] (X is pointer to array)
-       OSLICESTR    // X[Low : High] (X is string)
-       OSLICE3      // X[Low : High : Max] (X is untypedchecked or slice)
-       OSLICE3ARR   // X[Low : High : Max] (X is pointer to array)
-       OSLICEHEADER // sliceheader{Ptr, Len, Cap} (Ptr is unsafe.Pointer, Len is length, Cap is capacity)
-       ORECOVER     // recover()
-       ORECOVERFP   // recover(Args) w/ explicit FP argument
-       ORECV        // <-X
-       ORUNESTR     // Type(X) (Type is string, X is rune)
-       OSELRECV2    // like OAS2: Lhs = Rhs where len(Lhs)=2, len(Rhs)=1, Rhs[0].Op = ORECV (appears as .Var of OCASE)
-       OREAL        // real(X)
-       OIMAG        // imag(X)
-       OCOMPLEX     // complex(X, Y)
-       OALIGNOF     // unsafe.Alignof(X)
-       OOFFSETOF    // unsafe.Offsetof(X)
-       OSIZEOF      // unsafe.Sizeof(X)
-       OUNSAFEADD   // unsafe.Add(X, Y)
-       OUNSAFESLICE // unsafe.Slice(X, Y)
-       OMETHEXPR    // X(Args) (method expression T.Method(args), first argument is the method receiver)
-       OMETHVALUE   // X.Sel   (method expression t.Method, not called)
+       OMUL              // X * Y
+       ODIV              // X / Y
+       OMOD              // X % Y
+       OLSH              // X << Y
+       ORSH              // X >> Y
+       OAND              // X & Y
+       OANDNOT           // X &^ Y
+       ONEW              // new(X); corresponds to calls to new in source code
+       ONOT              // !X
+       OBITNOT           // ^X
+       OPLUS             // +X
+       ONEG              // -X
+       OOROR             // X || Y
+       OPANIC            // panic(X)
+       OPRINT            // print(List)
+       OPRINTN           // println(List)
+       OPAREN            // (X)
+       OSEND             // Chan <- Value
+       OSLICE            // X[Low : High] (X is untypechecked or slice)
+       OSLICEARR         // X[Low : High] (X is pointer to array)
+       OSLICESTR         // X[Low : High] (X is string)
+       OSLICE3           // X[Low : High : Max] (X is untypedchecked or slice)
+       OSLICE3ARR        // X[Low : High : Max] (X is pointer to array)
+       OSLICEHEADER      // sliceheader{Ptr, Len, Cap} (Ptr is unsafe.Pointer, Len is length, Cap is capacity)
+       OSTRINGHEADER     // stringheader{Ptr, Len} (Ptr is unsafe.Pointer, Len is length)
+       ORECOVER          // recover()
+       ORECOVERFP        // recover(Args) w/ explicit FP argument
+       ORECV             // <-X
+       ORUNESTR          // Type(X) (Type is string, X is rune)
+       OSELRECV2         // like OAS2: Lhs = Rhs where len(Lhs)=2, len(Rhs)=1, Rhs[0].Op = ORECV (appears as .Var of OCASE)
+       OREAL             // real(X)
+       OIMAG             // imag(X)
+       OCOMPLEX          // complex(X, Y)
+       OALIGNOF          // unsafe.Alignof(X)
+       OOFFSETOF         // unsafe.Offsetof(X)
+       OSIZEOF           // unsafe.Sizeof(X)
+       OUNSAFEADD        // unsafe.Add(X, Y)
+       OUNSAFESLICE      // unsafe.Slice(X, Y)
+       OUNSAFESLICEDATA  // unsafe.SliceData(X)
+       OUNSAFESTRING     // unsafe.String(X, Y)
+       OUNSAFESTRINGDATA // unsafe.StringData(X)
+       OMETHEXPR         // X(Args) (method expression T.Method(args), first argument is the method receiver)
+       OMETHVALUE        // X.Sel   (method expression t.Method, not called)
 
        // statements
        OBLOCK // { List } (block of code)
index 761af8abc583ded94a7ce61add4ee0624fc14885..f5d362eef543d18dc25d49498436b569f81f9180 100644 (file)
@@ -1146,6 +1146,34 @@ func (n *StarExpr) editChildren(edit func(Node) Node) {
        }
 }
 
+func (n *StringHeaderExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
+func (n *StringHeaderExpr) copy() Node {
+       c := *n
+       c.init = copyNodes(c.init)
+       return &c
+}
+func (n *StringHeaderExpr) doChildren(do func(Node) bool) bool {
+       if doNodes(n.init, do) {
+               return true
+       }
+       if n.Ptr != nil && do(n.Ptr) {
+               return true
+       }
+       if n.Len != nil && do(n.Len) {
+               return true
+       }
+       return false
+}
+func (n *StringHeaderExpr) editChildren(edit func(Node) Node) {
+       editNodes(n.init, edit)
+       if n.Ptr != nil {
+               n.Ptr = edit(n.Ptr).(Node)
+       }
+       if n.Len != nil {
+               n.Len = edit(n.Len).(Node)
+       }
+}
+
 func (n *StructKeyExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
 func (n *StructKeyExpr) copy() Node {
        c := *n
index 8ba7c207ce4c8613059662b579e32de5d8f1b647..e44168c7ba369751b33f37c126a5eb2febdb4fbf 100644 (file)
@@ -107,62 +107,66 @@ func _() {
        _ = x[OSLICE3-96]
        _ = x[OSLICE3ARR-97]
        _ = x[OSLICEHEADER-98]
-       _ = x[ORECOVER-99]
-       _ = x[ORECOVERFP-100]
-       _ = x[ORECV-101]
-       _ = x[ORUNESTR-102]
-       _ = x[OSELRECV2-103]
-       _ = x[OREAL-104]
-       _ = x[OIMAG-105]
-       _ = x[OCOMPLEX-106]
-       _ = x[OALIGNOF-107]
-       _ = x[OOFFSETOF-108]
-       _ = x[OSIZEOF-109]
-       _ = x[OUNSAFEADD-110]
-       _ = x[OUNSAFESLICE-111]
-       _ = x[OMETHEXPR-112]
-       _ = x[OMETHVALUE-113]
-       _ = x[OBLOCK-114]
-       _ = x[OBREAK-115]
-       _ = x[OCASE-116]
-       _ = x[OCONTINUE-117]
-       _ = x[ODEFER-118]
-       _ = x[OFALL-119]
-       _ = x[OFOR-120]
-       _ = x[OGOTO-121]
-       _ = x[OIF-122]
-       _ = x[OLABEL-123]
-       _ = x[OGO-124]
-       _ = x[ORANGE-125]
-       _ = x[ORETURN-126]
-       _ = x[OSELECT-127]
-       _ = x[OSWITCH-128]
-       _ = x[OTYPESW-129]
-       _ = x[OFUNCINST-130]
-       _ = x[OINLCALL-131]
-       _ = x[OEFACE-132]
-       _ = x[OITAB-133]
-       _ = x[OIDATA-134]
-       _ = x[OSPTR-135]
-       _ = x[OCFUNC-136]
-       _ = x[OCHECKNIL-137]
-       _ = x[ORESULT-138]
-       _ = x[OINLMARK-139]
-       _ = x[OLINKSYMOFFSET-140]
-       _ = x[OJUMPTABLE-141]
-       _ = x[ODYNAMICDOTTYPE-142]
-       _ = x[ODYNAMICDOTTYPE2-143]
-       _ = x[ODYNAMICTYPE-144]
-       _ = x[OTAILCALL-145]
-       _ = x[OGETG-146]
-       _ = x[OGETCALLERPC-147]
-       _ = x[OGETCALLERSP-148]
-       _ = x[OEND-149]
+       _ = x[OSTRINGHEADER-99]
+       _ = x[ORECOVER-100]
+       _ = x[ORECOVERFP-101]
+       _ = x[ORECV-102]
+       _ = x[ORUNESTR-103]
+       _ = x[OSELRECV2-104]
+       _ = x[OREAL-105]
+       _ = x[OIMAG-106]
+       _ = x[OCOMPLEX-107]
+       _ = x[OALIGNOF-108]
+       _ = x[OOFFSETOF-109]
+       _ = x[OSIZEOF-110]
+       _ = x[OUNSAFEADD-111]
+       _ = x[OUNSAFESLICE-112]
+       _ = x[OUNSAFESLICEDATA-113]
+       _ = x[OUNSAFESTRING-114]
+       _ = x[OUNSAFESTRINGDATA-115]
+       _ = x[OMETHEXPR-116]
+       _ = x[OMETHVALUE-117]
+       _ = x[OBLOCK-118]
+       _ = x[OBREAK-119]
+       _ = x[OCASE-120]
+       _ = x[OCONTINUE-121]
+       _ = x[ODEFER-122]
+       _ = x[OFALL-123]
+       _ = x[OFOR-124]
+       _ = x[OGOTO-125]
+       _ = x[OIF-126]
+       _ = x[OLABEL-127]
+       _ = x[OGO-128]
+       _ = x[ORANGE-129]
+       _ = x[ORETURN-130]
+       _ = x[OSELECT-131]
+       _ = x[OSWITCH-132]
+       _ = x[OTYPESW-133]
+       _ = x[OFUNCINST-134]
+       _ = x[OINLCALL-135]
+       _ = x[OEFACE-136]
+       _ = x[OITAB-137]
+       _ = x[OIDATA-138]
+       _ = x[OSPTR-139]
+       _ = x[OCFUNC-140]
+       _ = x[OCHECKNIL-141]
+       _ = x[ORESULT-142]
+       _ = x[OINLMARK-143]
+       _ = x[OLINKSYMOFFSET-144]
+       _ = x[OJUMPTABLE-145]
+       _ = x[ODYNAMICDOTTYPE-146]
+       _ = x[ODYNAMICDOTTYPE2-147]
+       _ = x[ODYNAMICTYPE-148]
+       _ = x[OTAILCALL-149]
+       _ = x[OGETG-150]
+       _ = x[OGETCALLERPC-151]
+       _ = x[OGETCALLERSP-152]
+       _ = x[OEND-153]
 }
 
-const _Op_name = "XXXNAMENONAMETYPELITERALNILADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESSLICE2ARRPTRASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVIDATACONVNOPCOPYDCLDCLFUNCDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERRECOVERRECOVERFPRECVRUNESTRSELRECV2REALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFUNSAFEADDUNSAFESLICEMETHEXPRMETHVALUEBLOCKBREAKCASECONTINUEDEFERFALLFORGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWFUNCINSTINLCALLEFACEITABIDATASPTRCFUNCCHECKNILRESULTINLMARKLINKSYMOFFSETJUMPTABLEDYNAMICDOTTYPEDYNAMICDOTTYPE2DYNAMICTYPETAILCALLGETGGETCALLERPCGETCALLERSPEND"
+const _Op_name = "XXXNAMENONAMETYPELITERALNILADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESSLICE2ARRPTRASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVIDATACONVNOPCOPYDCLDCLFUNCDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERSTRINGHEADERRECOVERRECOVERFPRECVRUNESTRSELRECV2REALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFUNSAFEADDUNSAFESLICEUNSAFESLICEDATAUNSAFESTRINGUNSAFESTRINGDATAMETHEXPRMETHVALUEBLOCKBREAKCASECONTINUEDEFERFALLFORGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWFUNCINSTINLCALLEFACEITABIDATASPTRCFUNCCHECKNILRESULTINLMARKLINKSYMOFFSETJUMPTABLEDYNAMICDOTTYPEDYNAMICDOTTYPE2DYNAMICTYPETAILCALLGETGGETCALLERPCGETCALLERSPEND"
 
-var _Op_index = [...]uint16{0, 3, 7, 13, 17, 24, 27, 30, 33, 35, 38, 44, 48, 54, 60, 69, 81, 90, 99, 111, 120, 132, 134, 137, 147, 154, 161, 168, 172, 176, 184, 192, 201, 204, 209, 216, 223, 229, 238, 246, 254, 260, 264, 273, 282, 289, 293, 296, 303, 311, 318, 324, 327, 333, 340, 348, 352, 359, 367, 369, 371, 373, 375, 377, 379, 384, 389, 397, 400, 409, 412, 416, 424, 431, 440, 453, 456, 459, 462, 465, 468, 471, 477, 480, 483, 489, 493, 496, 500, 505, 510, 516, 521, 525, 530, 538, 546, 552, 561, 572, 579, 588, 592, 599, 607, 611, 615, 622, 629, 637, 643, 652, 663, 671, 680, 685, 690, 694, 702, 707, 711, 714, 718, 720, 725, 727, 732, 738, 744, 750, 756, 764, 771, 776, 780, 785, 789, 794, 802, 808, 815, 828, 837, 851, 866, 877, 885, 889, 900, 911, 914}
+var _Op_index = [...]uint16{0, 3, 7, 13, 17, 24, 27, 30, 33, 35, 38, 44, 48, 54, 60, 69, 81, 90, 99, 111, 120, 132, 134, 137, 147, 154, 161, 168, 172, 176, 184, 192, 201, 204, 209, 216, 223, 229, 238, 246, 254, 260, 264, 273, 282, 289, 293, 296, 303, 311, 318, 324, 327, 333, 340, 348, 352, 359, 367, 369, 371, 373, 375, 377, 379, 384, 389, 397, 400, 409, 412, 416, 424, 431, 440, 453, 456, 459, 462, 465, 468, 471, 477, 480, 483, 489, 493, 496, 500, 505, 510, 516, 521, 525, 530, 538, 546, 552, 561, 572, 584, 591, 600, 604, 611, 619, 623, 627, 634, 641, 649, 655, 664, 675, 690, 702, 718, 726, 735, 740, 745, 749, 757, 762, 766, 769, 773, 775, 780, 782, 787, 793, 799, 805, 811, 819, 826, 831, 835, 840, 844, 849, 857, 863, 870, 883, 892, 906, 921, 932, 940, 944, 955, 966, 969}
 
 func (i Op) String() string {
        if i >= Op(len(_Op_index)-1) {
index 87068a9412be105f279bfbc3cd2c491a4cf91d53..15adb89e5f6c4b7704129edb03ba4ad5383bebd0 100644 (file)
@@ -900,7 +900,7 @@ func transformBuiltin(n *ir.CallExpr) ir.Node {
                transformArgs(n)
                fallthrough
 
-       case ir.ONEW, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
+       case ir.ONEW, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF, ir.OUNSAFESLICEDATA, ir.OUNSAFESTRINGDATA:
                u := ir.NewUnaryExpr(n.Pos(), op, n.Args[0])
                u1 := typed(n.Type(), ir.InitExpr(n.Init(), u)) // typecheckargs can add to old.Init
                switch op {
@@ -913,12 +913,12 @@ func transformBuiltin(n *ir.CallExpr) ir.Node {
                case ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
                        // This corresponds to the EvalConst() call near end of typecheck().
                        return typecheck.EvalConst(u1)
-               case ir.OCLOSE, ir.ONEW:
+               case ir.OCLOSE, ir.ONEW, ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
                        // nothing more to do
                        return u1
                }
 
-       case ir.OCOMPLEX, ir.OCOPY, ir.OUNSAFEADD, ir.OUNSAFESLICE:
+       case ir.OCOMPLEX, ir.OCOPY, ir.OUNSAFEADD, ir.OUNSAFESLICE, ir.OUNSAFESTRING:
                transformArgs(n)
                b := ir.NewBinaryExpr(n.Pos(), op, n.Args[0], n.Args[1])
                n1 := typed(n.Type(), ir.InitExpr(n.Init(), b))
index cef842ceb01aade93287dbe45ff857fa02f30d39..b72f795b4bfbaea0c12c1d2f43ef060ac46b301c 100644 (file)
@@ -1460,7 +1460,7 @@ func (s *state) stmt(n ir.Node) {
                s.callResult(n, callNormal)
                if n.Op() == ir.OCALLFUNC && n.X.Op() == ir.ONAME && n.X.(*ir.Name).Class == ir.PFUNC {
                        if fn := n.X.Sym().Name; base.Flag.CompilingRuntime && fn == "throw" ||
-                               n.X.Sym().Pkg == ir.Pkgs.Runtime && (fn == "throwinit" || fn == "gopanic" || fn == "panicwrap" || fn == "block" || fn == "panicmakeslicelen" || fn == "panicmakeslicecap" || fn == "panicunsafeslicelen" || fn == "panicunsafeslicenilptr") {
+                               n.X.Sym().Pkg == ir.Pkgs.Runtime && (fn == "throwinit" || fn == "gopanic" || fn == "panicwrap" || fn == "block" || fn == "panicmakeslicelen" || fn == "panicmakeslicecap" || fn == "panicunsafeslicelen" || fn == "panicunsafeslicenilptr" || fn == "panicunsafestringlen" || fn == "panicunsafestringnilptr") {
                                m := s.mem()
                                b := s.endBlock()
                                b.Kind = ssa.BlockExit
@@ -3242,6 +3242,12 @@ func (s *state) exprCheckPtr(n ir.Node, checkPtrOK bool) *ssa.Value {
                c := s.expr(n.Cap)
                return s.newValue3(ssa.OpSliceMake, n.Type(), p, l, c)
 
+       case ir.OSTRINGHEADER:
+               n := n.(*ir.StringHeaderExpr)
+               p := s.expr(n.Ptr)
+               l := s.expr(n.Len)
+               return s.newValue2(ssa.OpStringMake, n.Type(), p, l)
+
        case ir.OSLICE, ir.OSLICEARR, ir.OSLICE3, ir.OSLICE3ARR:
                n := n.(*ir.SliceExpr)
                check := s.checkPtrEnabled && n.Op() == ir.OSLICE3ARR && n.X.Op() == ir.OCONVNOP && n.X.(*ir.ConvExpr).X.Type().IsUnsafePtr()
index b2c8b5736abb47d908d1dcba5756d452f1546a9e..926234b40b34205ba0dd1fe4815829561e8690e7 100644 (file)
@@ -137,76 +137,79 @@ var runtimeDecls = [...]struct {
        {"unsafeslicecheckptr", funcTag, 118},
        {"panicunsafeslicelen", funcTag, 9},
        {"panicunsafeslicenilptr", funcTag, 9},
-       {"mulUintptr", funcTag, 119},
-       {"memmove", funcTag, 120},
-       {"memclrNoHeapPointers", funcTag, 121},
-       {"memclrHasPointers", funcTag, 121},
-       {"memequal", funcTag, 122},
-       {"memequal0", funcTag, 123},
-       {"memequal8", funcTag, 123},
-       {"memequal16", funcTag, 123},
-       {"memequal32", funcTag, 123},
-       {"memequal64", funcTag, 123},
-       {"memequal128", funcTag, 123},
-       {"f32equal", funcTag, 124},
-       {"f64equal", funcTag, 124},
-       {"c64equal", funcTag, 124},
-       {"c128equal", funcTag, 124},
-       {"strequal", funcTag, 124},
-       {"interequal", funcTag, 124},
-       {"nilinterequal", funcTag, 124},
-       {"memhash", funcTag, 125},
-       {"memhash0", funcTag, 126},
-       {"memhash8", funcTag, 126},
-       {"memhash16", funcTag, 126},
-       {"memhash32", funcTag, 126},
-       {"memhash64", funcTag, 126},
-       {"memhash128", funcTag, 126},
-       {"f32hash", funcTag, 126},
-       {"f64hash", funcTag, 126},
-       {"c64hash", funcTag, 126},
-       {"c128hash", funcTag, 126},
-       {"strhash", funcTag, 126},
-       {"interhash", funcTag, 126},
-       {"nilinterhash", funcTag, 126},
-       {"int64div", funcTag, 127},
-       {"uint64div", funcTag, 128},
-       {"int64mod", funcTag, 127},
-       {"uint64mod", funcTag, 128},
-       {"float64toint64", funcTag, 129},
-       {"float64touint64", funcTag, 130},
-       {"float64touint32", funcTag, 131},
-       {"int64tofloat64", funcTag, 132},
-       {"int64tofloat32", funcTag, 134},
-       {"uint64tofloat64", funcTag, 135},
-       {"uint64tofloat32", funcTag, 136},
-       {"uint32tofloat64", funcTag, 137},
-       {"complex128div", funcTag, 138},
-       {"getcallerpc", funcTag, 139},
-       {"getcallersp", funcTag, 139},
+       {"unsafestringcheckptr", funcTag, 119},
+       {"panicunsafestringlen", funcTag, 9},
+       {"panicunsafestringnilptr", funcTag, 9},
+       {"mulUintptr", funcTag, 120},
+       {"memmove", funcTag, 121},
+       {"memclrNoHeapPointers", funcTag, 122},
+       {"memclrHasPointers", funcTag, 122},
+       {"memequal", funcTag, 123},
+       {"memequal0", funcTag, 124},
+       {"memequal8", funcTag, 124},
+       {"memequal16", funcTag, 124},
+       {"memequal32", funcTag, 124},
+       {"memequal64", funcTag, 124},
+       {"memequal128", funcTag, 124},
+       {"f32equal", funcTag, 125},
+       {"f64equal", funcTag, 125},
+       {"c64equal", funcTag, 125},
+       {"c128equal", funcTag, 125},
+       {"strequal", funcTag, 125},
+       {"interequal", funcTag, 125},
+       {"nilinterequal", funcTag, 125},
+       {"memhash", funcTag, 126},
+       {"memhash0", funcTag, 127},
+       {"memhash8", funcTag, 127},
+       {"memhash16", funcTag, 127},
+       {"memhash32", funcTag, 127},
+       {"memhash64", funcTag, 127},
+       {"memhash128", funcTag, 127},
+       {"f32hash", funcTag, 127},
+       {"f64hash", funcTag, 127},
+       {"c64hash", funcTag, 127},
+       {"c128hash", funcTag, 127},
+       {"strhash", funcTag, 127},
+       {"interhash", funcTag, 127},
+       {"nilinterhash", funcTag, 127},
+       {"int64div", funcTag, 128},
+       {"uint64div", funcTag, 129},
+       {"int64mod", funcTag, 128},
+       {"uint64mod", funcTag, 129},
+       {"float64toint64", funcTag, 130},
+       {"float64touint64", funcTag, 131},
+       {"float64touint32", funcTag, 132},
+       {"int64tofloat64", funcTag, 133},
+       {"int64tofloat32", funcTag, 135},
+       {"uint64tofloat64", funcTag, 136},
+       {"uint64tofloat32", funcTag, 137},
+       {"uint32tofloat64", funcTag, 138},
+       {"complex128div", funcTag, 139},
+       {"getcallerpc", funcTag, 140},
+       {"getcallersp", funcTag, 140},
        {"racefuncenter", funcTag, 31},
        {"racefuncexit", funcTag, 9},
        {"raceread", funcTag, 31},
        {"racewrite", funcTag, 31},
-       {"racereadrange", funcTag, 140},
-       {"racewriterange", funcTag, 140},
-       {"msanread", funcTag, 140},
-       {"msanwrite", funcTag, 140},
-       {"msanmove", funcTag, 141},
-       {"asanread", funcTag, 140},
-       {"asanwrite", funcTag, 140},
-       {"checkptrAlignment", funcTag, 142},
-       {"checkptrArithmetic", funcTag, 144},
-       {"libfuzzerTraceCmp1", funcTag, 145},
-       {"libfuzzerTraceCmp2", funcTag, 146},
-       {"libfuzzerTraceCmp4", funcTag, 147},
-       {"libfuzzerTraceCmp8", funcTag, 148},
-       {"libfuzzerTraceConstCmp1", funcTag, 145},
-       {"libfuzzerTraceConstCmp2", funcTag, 146},
-       {"libfuzzerTraceConstCmp4", funcTag, 147},
-       {"libfuzzerTraceConstCmp8", funcTag, 148},
-       {"libfuzzerHookStrCmp", funcTag, 149},
-       {"libfuzzerHookEqualFold", funcTag, 149},
+       {"racereadrange", funcTag, 141},
+       {"racewriterange", funcTag, 141},
+       {"msanread", funcTag, 141},
+       {"msanwrite", funcTag, 141},
+       {"msanmove", funcTag, 142},
+       {"asanread", funcTag, 141},
+       {"asanwrite", funcTag, 141},
+       {"checkptrAlignment", funcTag, 143},
+       {"checkptrArithmetic", funcTag, 145},
+       {"libfuzzerTraceCmp1", funcTag, 146},
+       {"libfuzzerTraceCmp2", funcTag, 147},
+       {"libfuzzerTraceCmp4", funcTag, 148},
+       {"libfuzzerTraceCmp8", funcTag, 149},
+       {"libfuzzerTraceConstCmp1", funcTag, 146},
+       {"libfuzzerTraceConstCmp2", funcTag, 147},
+       {"libfuzzerTraceConstCmp4", funcTag, 148},
+       {"libfuzzerTraceConstCmp8", funcTag, 149},
+       {"libfuzzerHookStrCmp", funcTag, 150},
+       {"libfuzzerHookEqualFold", funcTag, 150},
        {"x86HasPOPCNT", varTag, 6},
        {"x86HasSSE41", varTag, 6},
        {"x86HasFMA", varTag, 6},
@@ -230,7 +233,7 @@ func params(tlist ...*types.Type) []*types.Field {
 }
 
 func runtimeTypes() []*types.Type {
-       var typs [150]*types.Type
+       var typs [151]*types.Type
        typs[0] = types.ByteType
        typs[1] = types.NewPtr(typs[0])
        typs[2] = types.Types[types.TANY]
@@ -350,36 +353,37 @@ func runtimeTypes() []*types.Type {
        typs[116] = types.NewSlice(typs[2])
        typs[117] = newSig(params(typs[1], typs[116], typs[15]), params(typs[116]))
        typs[118] = newSig(params(typs[1], typs[7], typs[22]), nil)
-       typs[119] = newSig(params(typs[5], typs[5]), params(typs[5], typs[6]))
-       typs[120] = newSig(params(typs[3], typs[3], typs[5]), nil)
-       typs[121] = newSig(params(typs[7], typs[5]), nil)
-       typs[122] = newSig(params(typs[3], typs[3], typs[5]), params(typs[6]))
-       typs[123] = newSig(params(typs[3], typs[3]), params(typs[6]))
-       typs[124] = newSig(params(typs[7], typs[7]), params(typs[6]))
-       typs[125] = newSig(params(typs[7], typs[5], typs[5]), params(typs[5]))
-       typs[126] = newSig(params(typs[7], typs[5]), params(typs[5]))
-       typs[127] = newSig(params(typs[22], typs[22]), params(typs[22]))
-       typs[128] = newSig(params(typs[24], typs[24]), params(typs[24]))
-       typs[129] = newSig(params(typs[20]), params(typs[22]))
-       typs[130] = newSig(params(typs[20]), params(typs[24]))
-       typs[131] = newSig(params(typs[20]), params(typs[62]))
-       typs[132] = newSig(params(typs[22]), params(typs[20]))
-       typs[133] = types.Types[types.TFLOAT32]
-       typs[134] = newSig(params(typs[22]), params(typs[133]))
-       typs[135] = newSig(params(typs[24]), params(typs[20]))
-       typs[136] = newSig(params(typs[24]), params(typs[133]))
-       typs[137] = newSig(params(typs[62]), params(typs[20]))
-       typs[138] = newSig(params(typs[26], typs[26]), params(typs[26]))
-       typs[139] = newSig(nil, params(typs[5]))
-       typs[140] = newSig(params(typs[5], typs[5]), nil)
-       typs[141] = newSig(params(typs[5], typs[5], typs[5]), nil)
-       typs[142] = newSig(params(typs[7], typs[1], typs[5]), nil)
-       typs[143] = types.NewSlice(typs[7])
-       typs[144] = newSig(params(typs[7], typs[143]), nil)
-       typs[145] = newSig(params(typs[66], typs[66], typs[15]), nil)
-       typs[146] = newSig(params(typs[60], typs[60], typs[15]), nil)
-       typs[147] = newSig(params(typs[62], typs[62], typs[15]), nil)
-       typs[148] = newSig(params(typs[24], typs[24], typs[15]), nil)
-       typs[149] = newSig(params(typs[28], typs[28], typs[15]), nil)
+       typs[119] = newSig(params(typs[7], typs[22]), nil)
+       typs[120] = newSig(params(typs[5], typs[5]), params(typs[5], typs[6]))
+       typs[121] = newSig(params(typs[3], typs[3], typs[5]), nil)
+       typs[122] = newSig(params(typs[7], typs[5]), nil)
+       typs[123] = newSig(params(typs[3], typs[3], typs[5]), params(typs[6]))
+       typs[124] = newSig(params(typs[3], typs[3]), params(typs[6]))
+       typs[125] = newSig(params(typs[7], typs[7]), params(typs[6]))
+       typs[126] = newSig(params(typs[7], typs[5], typs[5]), params(typs[5]))
+       typs[127] = newSig(params(typs[7], typs[5]), params(typs[5]))
+       typs[128] = newSig(params(typs[22], typs[22]), params(typs[22]))
+       typs[129] = newSig(params(typs[24], typs[24]), params(typs[24]))
+       typs[130] = newSig(params(typs[20]), params(typs[22]))
+       typs[131] = newSig(params(typs[20]), params(typs[24]))
+       typs[132] = newSig(params(typs[20]), params(typs[62]))
+       typs[133] = newSig(params(typs[22]), params(typs[20]))
+       typs[134] = types.Types[types.TFLOAT32]
+       typs[135] = newSig(params(typs[22]), params(typs[134]))
+       typs[136] = newSig(params(typs[24]), params(typs[20]))
+       typs[137] = newSig(params(typs[24]), params(typs[134]))
+       typs[138] = newSig(params(typs[62]), params(typs[20]))
+       typs[139] = newSig(params(typs[26], typs[26]), params(typs[26]))
+       typs[140] = newSig(nil, params(typs[5]))
+       typs[141] = newSig(params(typs[5], typs[5]), nil)
+       typs[142] = newSig(params(typs[5], typs[5], typs[5]), nil)
+       typs[143] = newSig(params(typs[7], typs[1], typs[5]), nil)
+       typs[144] = types.NewSlice(typs[7])
+       typs[145] = newSig(params(typs[7], typs[144]), nil)
+       typs[146] = newSig(params(typs[66], typs[66], typs[15]), nil)
+       typs[147] = newSig(params(typs[60], typs[60], typs[15]), nil)
+       typs[148] = newSig(params(typs[62], typs[62], typs[15]), nil)
+       typs[149] = newSig(params(typs[24], typs[24], typs[15]), nil)
+       typs[150] = newSig(params(typs[28], typs[28], typs[15]), nil)
        return typs[:]
 }
index 2a07ea1731faea576a5c39e00d25a4e509a59f73..ebe346c68b0be3a016d21ef6b93c6007041ca5d0 100644 (file)
@@ -183,6 +183,9 @@ func growslice(typ *byte, old []any, cap int) (ary []any)
 func unsafeslicecheckptr(typ *byte, ptr unsafe.Pointer, len int64)
 func panicunsafeslicelen()
 func panicunsafeslicenilptr()
+func unsafestringcheckptr(ptr unsafe.Pointer, len int64)
+func panicunsafestringlen()
+func panicunsafestringnilptr()
 
 func mulUintptr(x, y uintptr) (uintptr, bool)
 
index 6109850c242552ec6b389eaf2ebc0a1ecff9b00f..edc399ffd74c77f3e646032f1b1184aa0dbd6b9b 100644 (file)
@@ -758,7 +758,10 @@ func callOrChan(n ir.Node) bool {
                ir.ORECOVER,
                ir.ORECV,
                ir.OUNSAFEADD,
-               ir.OUNSAFESLICE:
+               ir.OUNSAFESLICE,
+               ir.OUNSAFESLICEDATA,
+               ir.OUNSAFESTRING,
+               ir.OUNSAFESTRINGDATA:
                return true
        }
        return false
index b69fc2d60da3995b2b450a379b679cbca2c2cff9..96f368363a2c65ddb1a1f45a53060608f8eb3af7 100644 (file)
@@ -659,6 +659,40 @@ func tcLenCap(n *ir.UnaryExpr) ir.Node {
        return n
 }
 
+// tcUnsafeData typechecks an OUNSAFESLICEDATA or OUNSAFESTRINGDATA node.
+func tcUnsafeData(n *ir.UnaryExpr) ir.Node {
+       n.X = Expr(n.X)
+       n.X = DefaultLit(n.X, nil)
+       l := n.X
+       t := l.Type()
+       if t == nil {
+               n.SetType(nil)
+               return n
+       }
+
+       var kind types.Kind
+       if n.Op() == ir.OUNSAFESLICEDATA {
+               kind = types.TSLICE
+       } else {
+               /* kind is string */
+               kind = types.TSTRING
+       }
+
+       if t.Kind() != kind {
+               base.Errorf("invalid argument %L for %v", l, n.Op())
+               n.SetType(nil)
+               return n
+       }
+
+       if kind == types.TSTRING {
+               t = types.ByteType
+       } else {
+               t = t.Elem()
+       }
+       n.SetType(types.NewPtr(t))
+       return n
+}
+
 // tcRecv typechecks an ORECV node.
 func tcRecv(n *ir.UnaryExpr) ir.Node {
        n.X = Expr(n.X)
@@ -812,6 +846,31 @@ func tcSliceHeader(n *ir.SliceHeaderExpr) ir.Node {
        return n
 }
 
+// tcStringHeader typechecks an OSTRINGHEADER node.
+func tcStringHeader(n *ir.StringHeaderExpr) ir.Node {
+       t := n.Type()
+       if t == nil {
+               base.Fatalf("no type specified for OSTRINGHEADER")
+       }
+
+       if !t.IsString() {
+               base.Fatalf("invalid type %v for OSTRINGHEADER", n.Type())
+       }
+
+       if n.Ptr == nil || n.Ptr.Type() == nil || !n.Ptr.Type().IsUnsafePtr() {
+               base.Fatalf("need unsafe.Pointer for OSTRINGHEADER")
+       }
+
+       n.Ptr = Expr(n.Ptr)
+       n.Len = DefaultLit(Expr(n.Len), types.Types[types.TINT])
+
+       if ir.IsConst(n.Len, constant.Int) && ir.Int64Val(n.Len) < 0 {
+               base.Fatalf("len for OSTRINGHEADER must be non-negative")
+       }
+
+       return n
+}
+
 // tcStar typechecks an ODEREF node, which may be an expression or a type.
 func tcStar(n *ir.StarExpr, top int) ir.Node {
        n.X = typecheck(n.X, ctxExpr|ctxType)
index 70ebc0e4572b435b2c13c458d719342ef14a73ec..18bc865e2692ca7343efae47c053f16f045d0ac8 100644 (file)
@@ -299,7 +299,7 @@ func tcCall(n *ir.CallExpr, top int) ir.Node {
                        n.SetTypecheck(0) // re-typechecking new op is OK, not a loop
                        return typecheck(n, top)
 
-               case ir.OCAP, ir.OCLOSE, ir.OIMAG, ir.OLEN, ir.OPANIC, ir.OREAL:
+               case ir.OCAP, ir.OCLOSE, ir.OIMAG, ir.OLEN, ir.OPANIC, ir.OREAL, ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
                        typecheckargs(n)
                        fallthrough
                case ir.ONEW, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
@@ -311,7 +311,7 @@ func tcCall(n *ir.CallExpr, top int) ir.Node {
                        u := ir.NewUnaryExpr(n.Pos(), l.BuiltinOp, arg)
                        return typecheck(ir.InitExpr(n.Init(), u), top) // typecheckargs can add to old.Init
 
-               case ir.OCOMPLEX, ir.OCOPY, ir.OUNSAFEADD, ir.OUNSAFESLICE:
+               case ir.OCOMPLEX, ir.OCOPY, ir.OUNSAFEADD, ir.OUNSAFESLICE, ir.OUNSAFESTRING:
                        typecheckargs(n)
                        arg1, arg2, ok := needTwoArgs(n)
                        if !ok {
@@ -907,10 +907,31 @@ func tcUnsafeSlice(n *ir.BinaryExpr) *ir.BinaryExpr {
                base.Errorf("unsafe.Slice of incomplete (or unallocatable) type not allowed")
        }
 
-       if !checkunsafeslice(&n.Y) {
+       if !checkunsafesliceorstring(n.Op(), &n.Y) {
                n.SetType(nil)
                return n
        }
        n.SetType(types.NewSlice(t.Elem()))
        return n
 }
+
+// tcUnsafeString typechecks an OUNSAFESTRING node.
+func tcUnsafeString(n *ir.BinaryExpr) *ir.BinaryExpr {
+       n.X = Expr(n.X)
+       n.Y = Expr(n.Y)
+       if n.X.Type() == nil || n.Y.Type() == nil {
+               n.SetType(nil)
+               return n
+       }
+       t := n.X.Type()
+       if !t.IsPtr() || !types.Identical(t.Elem(), types.Types[types.TUINT8]) {
+               base.Errorf("first argument to unsafe.String must be *byte; have %L", t)
+       }
+
+       if !checkunsafesliceorstring(n.Op(), &n.Y) {
+               n.SetType(nil)
+               return n
+       }
+       n.SetType(types.Types[types.TSTRING])
+       return n
+}
index f3af8f7ffec8548f109a579eb28e540e7dc15f1f..848408d240fa6a362d2bd677a89d2891d843554b 100644 (file)
@@ -1964,7 +1964,7 @@ func (w *exportWriter) expr(n ir.Node) {
                w.expr(n.Max)
                w.typ(n.Type())
 
-       case ir.OCOPY, ir.OCOMPLEX, ir.OUNSAFEADD, ir.OUNSAFESLICE:
+       case ir.OCOPY, ir.OCOMPLEX, ir.OUNSAFEADD, ir.OUNSAFESLICE, ir.OUNSAFESTRING:
                // treated like other builtin calls (see e.g., OREAL)
                n := n.(*ir.BinaryExpr)
                w.op(n.Op())
@@ -1982,7 +1982,7 @@ func (w *exportWriter) expr(n ir.Node) {
                w.expr(n.X)
                w.bool(n.Implicit())
 
-       case ir.OREAL, ir.OIMAG, ir.OCAP, ir.OCLOSE, ir.OLEN, ir.ONEW, ir.OPANIC:
+       case ir.OREAL, ir.OIMAG, ir.OCAP, ir.OCLOSE, ir.OLEN, ir.ONEW, ir.OPANIC, ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
                n := n.(*ir.UnaryExpr)
                w.op(n.Op())
                w.pos(n.Pos())
index 690daeed5ee3f5327fe237baa87f103fdd904817..85cac7af7970a4db53d9b76739d9102f7d92137d 100644 (file)
@@ -1494,16 +1494,18 @@ func (r *importReader) node() ir.Node {
                n.SetImplicit(r.bool())
                return n
 
-       case ir.OCOPY, ir.OCOMPLEX, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCAP, ir.OCLOSE, ir.ODELETE, ir.OLEN, ir.OMAKE, ir.ONEW, ir.OPANIC, ir.ORECOVER, ir.OPRINT, ir.OPRINTN, ir.OUNSAFEADD, ir.OUNSAFESLICE:
+       case ir.OCOPY, ir.OCOMPLEX, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCAP, ir.OCLOSE, ir.ODELETE, ir.OLEN, ir.OMAKE,
+               ir.ONEW, ir.OPANIC, ir.ORECOVER, ir.OPRINT, ir.OPRINTN,
+               ir.OUNSAFEADD, ir.OUNSAFESLICE, ir.OUNSAFESLICEDATA, ir.OUNSAFESTRING, ir.OUNSAFESTRINGDATA:
                pos := r.pos()
                switch op {
-               case ir.OCOPY, ir.OCOMPLEX, ir.OUNSAFEADD, ir.OUNSAFESLICE:
+               case ir.OCOPY, ir.OCOMPLEX, ir.OUNSAFEADD, ir.OUNSAFESLICE, ir.OUNSAFESTRING:
                        init := r.stmtList()
                        n := ir.NewBinaryExpr(pos, op, r.expr(), r.expr())
                        n.SetInit(init)
                        n.SetType(r.typ())
                        return n
-               case ir.OREAL, ir.OIMAG, ir.OCAP, ir.OCLOSE, ir.OLEN, ir.ONEW, ir.OPANIC:
+               case ir.OREAL, ir.OIMAG, ir.OCAP, ir.OCLOSE, ir.OLEN, ir.ONEW, ir.OPANIC, ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
                        n := ir.NewUnaryExpr(pos, op, r.expr())
                        if op != ir.OPANIC {
                                n.SetType(r.typ())
index 5693d5ffd49b7824298618b75e09bc52ec9aad8f..f4174d1a600b2b1a65d20607d171d88bb899ae2c 100644 (file)
@@ -610,6 +610,10 @@ func typecheck1(n ir.Node, top int) ir.Node {
                n := n.(*ir.SliceHeaderExpr)
                return tcSliceHeader(n)
 
+       case ir.OSTRINGHEADER:
+               n := n.(*ir.StringHeaderExpr)
+               return tcStringHeader(n)
+
        case ir.OMAKESLICECOPY:
                n := n.(*ir.MakeExpr)
                return tcMakeSliceCopy(n)
@@ -692,6 +696,18 @@ func typecheck1(n ir.Node, top int) ir.Node {
                n := n.(*ir.BinaryExpr)
                return tcUnsafeSlice(n)
 
+       case ir.OUNSAFESLICEDATA:
+               n := n.(*ir.UnaryExpr)
+               return tcUnsafeData(n)
+
+       case ir.OUNSAFESTRING:
+               n := n.(*ir.BinaryExpr)
+               return tcUnsafeString(n)
+
+       case ir.OUNSAFESTRINGDATA:
+               n := n.(*ir.UnaryExpr)
+               return tcUnsafeData(n)
+
        case ir.OCLOSURE:
                n := n.(*ir.ClosureExpr)
                return tcClosure(n, top)
@@ -1647,11 +1663,11 @@ func checkmake(t *types.Type, arg string, np *ir.Node) bool {
        return true
 }
 
-// checkunsafeslice is like checkmake but for unsafe.Slice.
-func checkunsafeslice(np *ir.Node) bool {
+// checkunsafesliceorstring is like checkmake but for unsafe.{Slice,String}.
+func checkunsafesliceorstring(op ir.Op, np *ir.Node) bool {
        n := *np
        if !n.Type().IsInteger() && n.Type().Kind() != types.TIDEAL {
-               base.Errorf("non-integer len argument in unsafe.Slice - %v", n.Type())
+               base.Errorf("non-integer len argument in %v - %v", op, n.Type())
                return false
        }
 
@@ -1660,11 +1676,11 @@ func checkunsafeslice(np *ir.Node) bool {
        if n.Op() == ir.OLITERAL {
                v := toint(n.Val())
                if constant.Sign(v) < 0 {
-                       base.Errorf("negative len argument in unsafe.Slice")
+                       base.Errorf("negative len argument in %v", op)
                        return false
                }
                if ir.ConstOverflow(v, types.Types[types.TINT]) {
-                       base.Errorf("len argument too large in unsafe.Slice")
+                       base.Errorf("len argument too large in %v", op)
                        return false
                }
        }
index 19cb244d58eb0bcd6ae128a3e49b4eff7eb61ebe..828a8db3e7f71ade3c3f3c62e29e0a9b6002cc79 100644 (file)
@@ -58,6 +58,9 @@ var unsafeFuncs = [...]struct {
        {"Offsetof", ir.OOFFSETOF},
        {"Sizeof", ir.OSIZEOF},
        {"Slice", ir.OUNSAFESLICE},
+       {"SliceData", ir.OUNSAFESLICEDATA},
+       {"String", ir.OUNSAFESTRING},
+       {"StringData", ir.OUNSAFESTRINGDATA},
 }
 
 // InitUniverse initializes the universe block.
index 5a649c0951277ec8a5a791c2eb440ab9c6d2f6f4..f96ee22f59fd847e57171ad6088fe85ddd170efe 100644 (file)
@@ -642,6 +642,14 @@ func walkRecoverFP(nn *ir.CallExpr, init *ir.Nodes) ir.Node {
        return mkcall("gorecover", nn.Type(), init, walkExpr(nn.Args[0], init))
 }
 
+// walkUnsafeData walks an OUNSAFESLICEDATA or OUNSAFESTRINGDATA expression.
+func walkUnsafeData(n *ir.UnaryExpr, init *ir.Nodes) ir.Node {
+       slice := walkExpr(n.X, init)
+       res := typecheck.Expr(ir.NewUnaryExpr(n.Pos(), ir.OSPTR, slice))
+       res.SetType(n.Type())
+       return walkExpr(res, init)
+}
+
 func walkUnsafeSlice(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
        ptr := safeExpr(n.X, init)
        len := safeExpr(n.Y, init)
@@ -731,6 +739,64 @@ func walkUnsafeSlice(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
        return walkExpr(typecheck.Expr(h), init)
 }
 
+func walkUnsafeString(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
+       ptr := safeExpr(n.X, init)
+       len := safeExpr(n.Y, init)
+
+       lenType := types.Types[types.TINT64]
+       unsafePtr := typecheck.Conv(ptr, types.Types[types.TUNSAFEPTR])
+
+       // If checkptr enabled, call runtime.unsafestringcheckptr to check ptr and len.
+       // for simplicity, unsafestringcheckptr always uses int64.
+       // Type checking guarantees that TIDEAL len are positive and fit in an int.
+       if ir.ShouldCheckPtr(ir.CurFunc, 1) {
+               fnname := "unsafestringcheckptr"
+               fn := typecheck.LookupRuntime(fnname)
+               init.Append(mkcall1(fn, nil, init, unsafePtr, typecheck.Conv(len, lenType)))
+       } else {
+               // Otherwise, open code unsafe.String to prevent runtime call overhead.
+               // Keep this code in sync with runtime.unsafestring{,64}
+               if len.Type().IsKind(types.TIDEAL) || len.Type().Size() <= types.Types[types.TUINT].Size() {
+                       lenType = types.Types[types.TINT]
+               } else {
+                       // len64 := int64(len)
+                       // if int64(int(len64)) != len64 {
+                       //     panicunsafestringlen()
+                       // }
+                       len64 := typecheck.Conv(len, lenType)
+                       nif := ir.NewIfStmt(base.Pos, nil, nil, nil)
+                       nif.Cond = ir.NewBinaryExpr(base.Pos, ir.ONE, typecheck.Conv(typecheck.Conv(len64, types.Types[types.TINT]), lenType), len64)
+                       nif.Body.Append(mkcall("panicunsafestringlen", nil, &nif.Body))
+                       appendWalkStmt(init, nif)
+               }
+
+               // if len < 0 { panicunsafestringlen() }
+               nif := ir.NewIfStmt(base.Pos, nil, nil, nil)
+               nif.Cond = ir.NewBinaryExpr(base.Pos, ir.OLT, typecheck.Conv(len, lenType), ir.NewInt(0))
+               nif.Body.Append(mkcall("panicunsafestringlen", nil, &nif.Body))
+               appendWalkStmt(init, nif)
+
+               // if uintpr(len) > -uintptr(ptr) {
+               //    if ptr == nil {
+               //       panicunsafestringnilptr()
+               //    }
+               //    panicunsafeslicelen()
+               // }
+               nifLen := ir.NewIfStmt(base.Pos, nil, nil, nil)
+               nifLen.Cond = ir.NewBinaryExpr(base.Pos, ir.OGT, typecheck.Conv(len, types.Types[types.TUINTPTR]), ir.NewUnaryExpr(base.Pos, ir.ONEG, typecheck.Conv(unsafePtr, types.Types[types.TUINTPTR])))
+               nifPtr := ir.NewIfStmt(base.Pos, nil, nil, nil)
+               nifPtr.Cond = ir.NewBinaryExpr(base.Pos, ir.OEQ, unsafePtr, typecheck.NodNil())
+               nifPtr.Body.Append(mkcall("panicunsafestringnilptr", nil, &nifPtr.Body))
+               nifLen.Body.Append(nifPtr, mkcall("panicunsafestringlen", nil, &nifLen.Body))
+               appendWalkStmt(init, nifLen)
+       }
+       h := ir.NewStringHeaderExpr(n.Pos(),
+               typecheck.Conv(ptr, types.Types[types.TUNSAFEPTR]),
+               typecheck.Conv(len, types.Types[types.TINT]),
+       )
+       return walkExpr(typecheck.Expr(h), init)
+}
+
 func badtype(op ir.Op, tl, tr *types.Type) {
        var s string
        if tl != nil {
index c80bc3d80bf3df7d4b9ca3d34e191eb12ba16ab0..2842c53df256e8bd907d821b71e5729963c2d3fb 100644 (file)
@@ -129,6 +129,14 @@ func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node {
                n := n.(*ir.BinaryExpr)
                return walkUnsafeSlice(n, init)
 
+       case ir.OUNSAFESTRING:
+               n := n.(*ir.BinaryExpr)
+               return walkUnsafeString(n, init)
+
+       case ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
+               n := n.(*ir.UnaryExpr)
+               return walkUnsafeData(n, init)
+
        case ir.ODOT, ir.ODOTPTR:
                n := n.(*ir.SelectorExpr)
                return walkDot(n, init)
@@ -244,6 +252,10 @@ func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node {
                n := n.(*ir.SliceHeaderExpr)
                return walkSliceHeader(n, init)
 
+       case ir.OSTRINGHEADER:
+               n := n.(*ir.StringHeaderExpr)
+               return walkStringHeader(n, init)
+
        case ir.OSLICE, ir.OSLICEARR, ir.OSLICESTR, ir.OSLICE3, ir.OSLICE3ARR:
                n := n.(*ir.SliceExpr)
                return walkSlice(n, init)
@@ -849,6 +861,13 @@ func walkSliceHeader(n *ir.SliceHeaderExpr, init *ir.Nodes) ir.Node {
        return n
 }
 
+// walkStringHeader walks an OSTRINGHEADER node.
+func walkStringHeader(n *ir.StringHeaderExpr, init *ir.Nodes) ir.Node {
+       n.Ptr = walkExpr(n.Ptr, init)
+       n.Len = walkExpr(n.Len, init)
+       return n
+}
+
 // TODO(josharian): combine this with its caller and simplify
 func reduceSlice(n *ir.SliceExpr) ir.Node {
        if n.High != nil && n.High.Op() == ir.OLEN && ir.SameSafeExpr(n.X, n.High.(*ir.UnaryExpr).X) {
index 78cc2e69da091b1acf00109c036980bd69dd665f..d6b09866f71e91b7b6e6742edd5c9ec0329de340 100644 (file)
@@ -342,7 +342,7 @@ func mayCall(n ir.Node) bool {
                        ir.OCAP, ir.OIMAG, ir.OLEN, ir.OREAL,
                        ir.OCONVNOP, ir.ODOT,
                        ir.OCFUNC, ir.OIDATA, ir.OITAB, ir.OSPTR,
-                       ir.OBYTES2STRTMP, ir.OGETG, ir.OGETCALLERPC, ir.OGETCALLERSP, ir.OSLICEHEADER:
+                       ir.OBYTES2STRTMP, ir.OGETG, ir.OGETCALLERPC, ir.OGETCALLERSP, ir.OSLICEHEADER, ir.OSTRINGHEADER:
                        // ok: operations that don't require function calls.
                        // Expand as needed.
                }
index 15011ec494ad6c69b4958532613bdac9f65d87a0..811c0f035534205684740b9569d0c26785315cd3 100644 (file)
@@ -39,6 +39,8 @@ func TestCheckPtr(t *testing.T) {
                {"CheckPtrSmall", "fatal error: checkptr: pointer arithmetic computed bad pointer value\n"},
                {"CheckPtrSliceOK", ""},
                {"CheckPtrSliceFail", "fatal error: checkptr: unsafe.Slice result straddles multiple allocations\n"},
+               {"CheckPtrStringOK", ""},
+               {"CheckPtrStringFail", "fatal error: checkptr: unsafe.String result straddles multiple allocations\n"},
        }
 
        for _, tc := range testCases {
index e537f15826415961d9efa6c7f6b094f80cea55c7..0a203e4101f03351a0f41998c530282f8c153d73 100644 (file)
@@ -123,54 +123,6 @@ func mulUintptr(a, b uintptr) (uintptr, bool) {
        return math.MulUintptr(a, b)
 }
 
-// Keep this code in sync with cmd/compile/internal/walk/builtin.go:walkUnsafeSlice
-func unsafeslice(et *_type, ptr unsafe.Pointer, len int) {
-       if len < 0 {
-               panicunsafeslicelen()
-       }
-
-       if et.size == 0 {
-               if ptr == nil && len > 0 {
-                       panicunsafeslicenilptr()
-               }
-       }
-
-       mem, overflow := math.MulUintptr(et.size, uintptr(len))
-       if overflow || mem > -uintptr(ptr) {
-               if ptr == nil {
-                       panicunsafeslicenilptr()
-               }
-               panicunsafeslicelen()
-       }
-}
-
-// Keep this code in sync with cmd/compile/internal/walk/builtin.go:walkUnsafeSlice
-func unsafeslice64(et *_type, ptr unsafe.Pointer, len64 int64) {
-       len := int(len64)
-       if int64(len) != len64 {
-               panicunsafeslicelen()
-       }
-       unsafeslice(et, ptr, len)
-}
-
-func unsafeslicecheckptr(et *_type, ptr unsafe.Pointer, len64 int64) {
-       unsafeslice64(et, ptr, len64)
-
-       // Check that underlying array doesn't straddle multiple heap objects.
-       // unsafeslice64 has already checked for overflow.
-       if checkptrStraddles(ptr, uintptr(len64)*et.size) {
-               throw("checkptr: unsafe.Slice result straddles multiple allocations")
-       }
-}
-
-func panicunsafeslicelen() {
-       panic(errorString("unsafe.Slice: len out of range"))
-}
-
-func panicunsafeslicenilptr() {
-       panic(errorString("unsafe.Slice: ptr is nil and len is not zero"))
-}
-
 // growslice handles slice growth during append.
 // It is passed the slice element type, the old slice, and the desired new minimum capacity,
 // and it returns a new slice with at least that capacity, with the old data
index b27e5f74f868f3db8c31d60d745feac20f085cc8..60e71e66d7f4f5242624b589d7271091e3725169 100644 (file)
@@ -20,6 +20,8 @@ func init() {
        register("CheckPtrSmall", CheckPtrSmall)
        register("CheckPtrSliceOK", CheckPtrSliceOK)
        register("CheckPtrSliceFail", CheckPtrSliceFail)
+       register("CheckPtrStringOK", CheckPtrStringOK)
+       register("CheckPtrStringFail", CheckPtrStringFail)
        register("CheckPtrAlignmentNested", CheckPtrAlignmentNested)
 }
 
@@ -98,6 +100,17 @@ func CheckPtrSliceFail() {
        sink2 = unsafe.Slice(p, 100)
 }
 
+func CheckPtrStringOK() {
+       p := new([4]byte)
+       sink2 = unsafe.String(&p[1], 3)
+}
+
+func CheckPtrStringFail() {
+       p := new(byte)
+       sink2 = p
+       sink2 = unsafe.String(p, 100)
+}
+
 func CheckPtrAlignmentNested() {
        s := make([]int8, 100)
        p := unsafe.Pointer(&s[0])
diff --git a/src/runtime/unsafe.go b/src/runtime/unsafe.go
new file mode 100644 (file)
index 0000000..54649e8
--- /dev/null
@@ -0,0 +1,98 @@
+// Copyright 2022 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 runtime
+
+import (
+       "runtime/internal/math"
+       "unsafe"
+)
+
+func unsafestring(ptr unsafe.Pointer, len int) {
+       if len < 0 {
+               panicunsafestringlen()
+       }
+
+       if uintptr(len) > -uintptr(ptr) {
+               if ptr == nil {
+                       panicunsafestringnilptr()
+               }
+               panicunsafestringlen()
+       }
+}
+
+// Keep this code in sync with cmd/compile/internal/walk/builtin.go:walkUnsafeString
+func unsafestring64(ptr unsafe.Pointer, len64 int64) {
+       len := int(len64)
+       if int64(len) != len64 {
+               panicunsafestringlen()
+       }
+       unsafestring(ptr, len)
+}
+
+func unsafestringcheckptr(ptr unsafe.Pointer, len64 int64) {
+       unsafestring64(ptr, len64)
+
+       // Check that underlying array doesn't straddle multiple heap objects.
+       // unsafestring64 has already checked for overflow.
+       if checkptrStraddles(ptr, uintptr(len64)) {
+               throw("checkptr: unsafe.String result straddles multiple allocations")
+       }
+}
+
+func panicunsafestringlen() {
+       panic(errorString("unsafe.String: len out of range"))
+}
+
+func panicunsafestringnilptr() {
+       panic(errorString("unsafe.String: ptr is nil and len is not zero"))
+}
+
+// Keep this code in sync with cmd/compile/internal/walk/builtin.go:walkUnsafeSlice
+func unsafeslice(et *_type, ptr unsafe.Pointer, len int) {
+       if len < 0 {
+               panicunsafeslicelen()
+       }
+
+       if et.size == 0 {
+               if ptr == nil && len > 0 {
+                       panicunsafeslicenilptr()
+               }
+       }
+
+       mem, overflow := math.MulUintptr(et.size, uintptr(len))
+       if overflow || mem > -uintptr(ptr) {
+               if ptr == nil {
+                       panicunsafeslicenilptr()
+               }
+               panicunsafeslicelen()
+       }
+}
+
+// Keep this code in sync with cmd/compile/internal/walk/builtin.go:walkUnsafeSlice
+func unsafeslice64(et *_type, ptr unsafe.Pointer, len64 int64) {
+       len := int(len64)
+       if int64(len) != len64 {
+               panicunsafeslicelen()
+       }
+       unsafeslice(et, ptr, len)
+}
+
+func unsafeslicecheckptr(et *_type, ptr unsafe.Pointer, len64 int64) {
+       unsafeslice64(et, ptr, len64)
+
+       // Check that underlying array doesn't straddle multiple heap objects.
+       // unsafeslice64 has already checked for overflow.
+       if checkptrStraddles(ptr, uintptr(len64)*et.size) {
+               throw("checkptr: unsafe.Slice result straddles multiple allocations")
+       }
+}
+
+func panicunsafeslicelen() {
+       panic(errorString("unsafe.Slice: len out of range"))
+}
+
+func panicunsafeslicenilptr() {
+       panic(errorString("unsafe.Slice: ptr is nil and len is not zero"))
+}
diff --git a/test/unsafe_slice_data.go b/test/unsafe_slice_data.go
new file mode 100644 (file)
index 0000000..e8b8207
--- /dev/null
@@ -0,0 +1,22 @@
+// run
+
+// Copyright 2022 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 main
+
+import (
+       "fmt"
+       "reflect"
+       "unsafe"
+)
+
+func main() {
+       var s = []byte("abc")
+       sh1 := *(*reflect.SliceHeader)(unsafe.Pointer(&s))
+       ptr2 := unsafe.Pointer(unsafe.SliceData(s))
+       if ptr2 != unsafe.Pointer(sh1.Data) {
+               panic(fmt.Errorf("unsafe.SliceData %p != %p", ptr2, unsafe.Pointer(sh1.Data)))
+       }
+}
diff --git a/test/unsafe_string.go b/test/unsafe_string.go
new file mode 100644 (file)
index 0000000..ceecc6f
--- /dev/null
@@ -0,0 +1,18 @@
+// run
+
+// Copyright 2022 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 main
+
+import (
+       "unsafe"
+)
+
+func main() {
+       hello := [5]byte{'m', 'o', 's', 'h', 'i'}
+       if unsafe.String(&hello[0], uint64(len(hello))) != "moshi" {
+               panic("unsafe.String convert error")
+       }
+}
diff --git a/test/unsafe_string_data.go b/test/unsafe_string_data.go
new file mode 100644 (file)
index 0000000..a3a69af
--- /dev/null
@@ -0,0 +1,22 @@
+// run
+
+// Copyright 2022 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 main
+
+import (
+       "fmt"
+       "reflect"
+       "unsafe"
+)
+
+func main() {
+       var s = "abc"
+       sh1 := (*reflect.StringHeader)(unsafe.Pointer(&s))
+       ptr2 := unsafe.Pointer(unsafe.StringData(s))
+       if ptr2 != unsafe.Pointer(sh1.Data) {
+               panic(fmt.Errorf("unsafe.StringData ret %p != %p", ptr2, unsafe.Pointer(sh1.Data)))
+       }
+}
index d04bcbdc7d6a2f8f41d9c617791b8c8aa01661a7..8ee72ec2e8abdfab43dd489a4c41582cb71149ca 100644 (file)
@@ -53,6 +53,44 @@ func main() {
                _ = unsafe.Slice(last, 1)
                mustPanic(func() { _ = unsafe.Slice(last, 2) })
        }
+
+       // unsafe.String
+       {
+               s := unsafe.String(&p[0], len(p))
+               assert(s == string(p[:]))
+               assert(len(s) == len(p))
+
+               // the empty string
+               assert(unsafe.String(nil, 0) == "")
+
+               // nil pointer with positive length panics
+               mustPanic(func() { _ = unsafe.String(nil, 1) })
+
+               // negative length
+               var neg int = -1
+               mustPanic(func() { _ = unsafe.String(new(byte), neg) })
+
+               // length too large
+               var tooBig uint64 = math.MaxUint64
+               mustPanic(func() { _ = unsafe.String(new(byte), tooBig) })
+
+               // string memory overflows address space
+               last := (*byte)(unsafe.Pointer(^uintptr(0)))
+               _ = unsafe.String(last, 1)
+               mustPanic(func() { _ = unsafe.String(last, 2) })
+       }
+
+       // unsafe.StringData
+       {
+               var s = "string"
+               assert(string(unsafe.Slice(unsafe.StringData(s), len(s))) == s)
+       }
+
+       //unsafe.SliceData
+       {
+               var s = []byte("slice")
+               assert(unsafe.String(unsafe.SliceData(s), len(s)) == string(s))
+       }
 }
 
 func assert(ok bool) {